﻿using System;
using System.Collections;
using System.Collections.Generic;
using linq = Microsoft.Linq.Expressions;
using System.Linq;
using Bling.Util;

namespace Bling.DSL {
  public interface BaseBrand {
    Type TypeOfT { get; }
  }
  public abstract class Brand : BaseBrand {
    public abstract Type TypeOfT { get; }
    public static readonly Dictionary<Type, Type> ComponentTypes = new Dictionary<Type, Type>();
    public static readonly Dictionary<Type, Func<Expr, Brand>> Brands = new Dictionary<Type, Func<Expr, Brand>>();
    public static readonly Dictionary<Type, Func<Brand[], IntBl, Brand>> Tables =
      new Dictionary<Type, Func<Brand[], IntBl, Brand>>();
    public static readonly Dictionary<Type, Func<BoolBl, Brand, Brand, Brand>> Conditions =
      new Dictionary<Type, Func<BoolBl, Brand, Brand, Brand>>();
  }
  public abstract class Brand<T> : Brand, BaseBrandT<T> {
    public abstract Expr<T> Underlying { get; }
  }
  /// <summary>
  /// Just a marker.
  /// </summary>
  public interface BaseBrand<BRAND> : BaseBrand where BRAND : Brand, BaseBrand<BRAND> {
    BRAND Bind { get; set; }
  }
  public interface BaseBrandT<T> : BaseBrand {
    Expr<T> Underlying { get; }
  }
  public interface BaseBrand<T, BRAND> : BaseBrand<BRAND>, BaseBrandT<T> where BRAND : Brand<T, BRAND> { }


  /// <summary>
  ///  A branded Bl value that corresponds to a core language value. Branding adds operations and coercions to an underlying Bl value. 
  /// </summary>
  /// <typeparam name="T">Type of the corresponding core language value.</typeparam>
  /// <typeparam name="SELF">Branded type of the Bl value.</typeparam>
  public abstract partial class Brand<T, BRAND> : Brand<T>, BaseBrand<T,BRAND>
    where BRAND : Brand<T, BRAND> {

    public override Type TypeOfT { get { return typeof(T); } }

    public static BRAND DoTable(BRAND[] values, IntBl Index) {
        var values0 = new Expr<T>[values.Length];
        for (int i = 0; i < values.Length; i++) values0[i] = ((Brand<T,BRAND>)values[i]).Underlying;
        return ToBrand(new TableExpr<T>(values0, Index));
    }

    private static Func<Expr<T>, BRAND> Brand0;
    static Brand() {
      ComponentTypes[typeof(BRAND)] = typeof(T);
      Tables[typeof(BRAND)] = (values, index) => {
        var values0 = new Expr<T>[values.Length];
        for (int i = 0; i < values.Length; i++) values0[i] = ((Brand<T,BRAND>)values[i]).Underlying;
        return ToBrand(new TableExpr<T>(values0, index));
      };
      Conditions[typeof(BRAND)] = (condition, ifTrue, ifFalse) => {
        var ifTrue0 = ((Brand<T, BRAND>)ifTrue).Underlying;
        var ifFalse0 = ((Brand<T, BRAND>)ifFalse).Underlying;
        return ToBrand(Expr<T>.ConditionOp.Make(condition, ifTrue0, ifFalse0));
      };
    }
    protected static void Register(Func<Expr<T>, BRAND> Brand) {
      (Brand0 == null).Assert();
      Brand<T,BRAND>.Brand0 = Brand;
      Brands[typeof(T)] = v => Brand((Expr<T>) v);
    }
    public static BRAND ToBrand(Expr<T> Underlying) {
      (Underlying != null).Assert(); 
      return Brand0(Underlying); 
    }
    public static implicit operator BRAND(Brand<T, BRAND> v) { return (BRAND)v; }
    /// <summary>
    /// The underlying unbranded Bl value.
    /// </summary>
    private readonly Expr<T> BaseUnderlying;
    public override Expr<T> Underlying { get { return BaseUnderlying; } }
    public Brand(Expr<T> Underlying) {
      (Underlying != null).Assert();
      this.BaseUnderlying = Underlying;
    }

    public static implicit operator Expr<T>(Brand<T, BRAND> v) { return v.Underlying; }
    public override string ToString() {
      return Underlying.ToString();
    }
    public bool Assign(Assign P, BRAND to) {
      return Underlying.Solve(P, to.Underlying);
    }
    /// <summary>
    /// The current core language value of this Bl value. This operation will not be supported if the core language value is
    /// unavailable; e.g., the Bl value exists in a pixel shader.
    /// </summary>
    public T CurrentValue {
      get { return Underlying.CurrentValue; }
      //set { AssignNow(value); }
    }


    /// <summary>
    /// A function that returns the current core language vlaue of this Bl value. 
    /// Current means when the function is applied, same restrictions as in Value apply.
    /// </summary>
    public Func<T> AsFunc {
      get {
        if (true) {
          return Linq.DefaultLinqEval.Eval<T>(this);
        } else {
          var f = ((ApplyEval<object>.MyInfo<T>)Underlying.Eval(new ApplyEval<object>())).Value;
          return () => f(null);
        }
      }
    }
    public static Func<S, T> Func<S>(Func<Expr<S>, BRAND> value) {
      return Linq.DefaultLinqEval.Eval<S, T>(s => value(s));
    }
    public static Func<S, U, T> Func<S, U>(Func<Expr<S>, Expr<U>, BRAND> value) {
      return Linq.DefaultLinqEval.Eval<S, U, T>((s, u) => value(s, u));
    }
    public static Func<S, U, V, T> Func<S, U, V>(Func<Expr<S>, Expr<U>, Expr<V>, BRAND> value) {
      return Linq.DefaultLinqEval.Eval<S, U, V, T>((s, u, v) => value(s, u, v));
    }
    public static Func<S, U, V, W, T> Func<S, U, V, W>(Func<Expr<S>, Expr<U>, Expr<V>, Expr<W>, BRAND> value) {
      return Linq.DefaultLinqEval.Eval<S, U, V, W, T>((s, u, v, w) => value(s, u, v, w));
    }

    /// <summary>
    /// Binds this Bl value to another Bl value, where binding is continuous 
    /// (the bound value changes when the bound to value changes). 
    /// The definition of binding depends on the underlying Bl value; e.g., 
    /// databinding for a WPF dependency property or physical relaxation for a physical property value. 
    /// Not supported for pixel shader values.
    /// </summary>
    public BRAND Bind {
      get {
        return this;
      }
      set {
        Underlying.Bind = value;
      }
    }
    public Action<T> FuncAssign {
      get {
        Action<T> AssignNow0;
        {
          var assign = new NowAssign<T>();
          if (!Underlying.Solve(assign, assign.Argument))
            throw new NotSupportedException();
          var list = assign.Results;
          if (list.Count == 0) throw new NotSupportedException();
          else if (list.Count == 1) AssignNow0 = list[0];
          else AssignNow0 = (t) => {
            foreach (var v in list) v(t);
          };
        }
        return AssignNow0;
      }
    }

    /// <summary>
    /// Immediately assign this Bl value to the value of another Bl value.  Is not continuous like bind; e.g.,
    /// for dependency properties the local value is set.  The value returned by the accessor will always
    /// return the value at the time Now is accessed.
    /// </summary>
    public BRAND Now {
      get { return ToBrand(new NowExpr<T>(Underlying)); }
      set {
        Now.Bind = value;
      }
    }
    public class RefreshBl {
      internal BRAND LHS;
      /// <summary>
      /// Creates an assignment that is periodically re-executed by the specified refresh manager.
      /// </summary>
      /// <param name="m">Manager who controls when the value should be refreshed.</param>
      /// <returns>This Bl value.</returns>
      public BRAND this[RefreshManager m] {
        //get { return LHS; }
        set { m.Register(Assign(LHS, value), true); }
      }
      public class BidirectionalBl {
        internal BRAND LHS;
        public BRAND this[RefreshManager m, BoolBl direction] {
          set {
            m.Register(Assign(LHS, value), direction);
            m.Register(Assign(value, LHS), !direction);
          }
        }
      }

      public BidirectionalBl BiDirectional {
        get { return new BidirectionalBl() { LHS = LHS }; }
      }
    }
    /// <summary>
    /// Requires indexing.
    /// </summary>
    public RefreshBl Refresh {
      get { return new RefreshBl() { LHS = this }; }
    }
    /// <summary>
    /// Creates a function that executes the assignment LHS = RHS.
    /// </summary>
    /// <param name="LHS">The Bl value being assigned to.</param>
    /// <param name="RHS">The Bl value being assigned from.</param>
    /// <returns>Function that executes the assignment.</returns>
    public static Action Assign(BRAND LHS, BRAND RHS) {
      var assign = new NowAssign();
      if (!LHS.Underlying.Solve(assign, RHS)) throw new NotSupportedException();
      var list = assign.Results;
      if (list.Count == 1) {
        return list[0];
      } else return () => {
        foreach (var n in list) n();
      };
    }
    /// <summary>
    /// Creates a one argument function that executes the assignment s => LHS(s) = RHS(s), 
    /// where s is bound to the specified argument.
    /// </summary>
    /// <typeparam name="S">Type of the argument.</typeparam>
    /// <param name="LHS">Expression being assigned to.</param>
    /// <param name="RHS">Expression being assigned from.</param>
    /// <returns>Function that executes the assignment.</returns>
    public static Action<S> Assign<S>(Func<Expr<S>, BRAND> LHS, Func<Expr<S>, BRAND> RHS) {
      var assign = new NowAssign<S>();
      var RHS0 = RHS(assign.Argument);
      var LHS0 = LHS(assign.Argument);
      if (!LHS0.Underlying.Solve(assign, RHS0)) throw new NotSupportedException();
      var list = assign.Results;
      // flatten the list!
      if (list.Count == 0) throw new NotSupportedException();
      else if (list.Count == 1) return list[0];
      else return arg => {
        foreach (var n in list) n(arg);
      };
    }

    public static Action<S,U> Assign<S,U>(Func<Expr<S>, Expr<U>, BRAND> LHS, Func<Expr<S>, Expr<U>, BRAND> RHS) {
      var assign = new NowAssign<S,U>();
      var RHS0 = RHS(assign.ArgumentA, assign.ArgumentB);
      var LHS0 = LHS(assign.ArgumentA, assign.ArgumentB);
      if (!LHS0.Underlying.Solve(assign, RHS0)) throw new NotSupportedException();
      var list = assign.Results;
      // flatten the list!
      if (list.Count == 0) throw new NotSupportedException();
      else if (list.Count == 1) return list[0];
      else return (argA,argB) => {
        foreach (var n in list) n(argA,argB);
      };
    }
    public static Action<S, U, V> Assign<S, U, V>(Func<Expr<S>, Expr<U>, Expr<V>, BRAND> LHS, Func<Expr<S>, Expr<U>, Expr<V>, BRAND> RHS) {
      var assign = new NowAssign<S, U, V>();
      var RHS0 = RHS(assign.ArgumentA, assign.ArgumentB, assign.ArgumentC);
      var LHS0 = LHS(assign.ArgumentA, assign.ArgumentB, assign.ArgumentC);
      if (!LHS0.Underlying.Solve(assign, RHS0)) throw new NotSupportedException();
      var list = assign.Results;
      // flatten the list!
      if (list.Count == 0) throw new NotSupportedException();
      else if (list.Count == 1) return list[0];
      else return (argA, argB, argC) => {
        foreach (var n in list) n(argA, argB, argC);
      };
    }
    public static Action<S, U, V, W> Assign<S, U, V, W>(Func<Expr<S>, Expr<U>, Expr<V>, Expr<W>, BRAND> LHS, Func<Expr<S>, Expr<U>, Expr<V>, Expr<W>, BRAND> RHS) {
      var assign = new NowAssign<S, U, V, W>();
      var RHS0 = RHS(assign.ArgumentA, assign.ArgumentB, assign.ArgumentC, assign.ArgumentD);
      var LHS0 = LHS(assign.ArgumentA, assign.ArgumentB, assign.ArgumentC, assign.ArgumentD);
      if (!LHS0.Underlying.Solve(assign, RHS0)) throw new NotSupportedException();
      var list = assign.Results;
      // flatten the list!
      if (list.Count == 0) throw new NotSupportedException();
      else if (list.Count == 1) return list[0];
      else return (argA, argB, argC, argD) => {
        foreach (var n in list) n(argA, argB, argC, argD);
      };
    }


    /// <summary>
    /// Creates a one argument function that executes the assignment s => LHS(s) = RHS(s), 
    /// where s is bound to the specified integer argument.
    /// </summary>
    /// <param name="LHS">Expression being assigned to.</param>
    /// <param name="RHS">Expression being assigned from.</param>
    /// <returns></returns>
    public static Action<int> MakeNowInt(Func<IntBl, BRAND> LHS, Func<IntBl, BRAND> RHS) {
      return Assign<int>(i => LHS(i.Bl()), i => RHS(i.Bl()));
    }

    /*
    protected static Operator<S, T> UpCast<S>() where S : T {
      return new Operator<S, T>(Markers.UpCastMarker) {
        Apply = a => a,
       
      };
    }*/
    protected static readonly Operator<T, string> ToStringOp = new Operator<T, string>(Markers.ToStringMarker) {
      Apply = a => a.ToString(),
    };
    /// <summary>
    /// Convert this Bl value into a branded object Bl value.
    /// </summary>
    public ObjectBl ToObject() {
        return ObjectBl.UpCast<T>(this);
    }
    /// <summary>
    /// Convert this Bl value into a branded string Bl value. Unlike ToString, this string will update as the underlying value changes.
    /// </summary>
    public virtual StringBl ToStringBl() {
      return ToStringOp.Make(this); 
    }
    public static implicit operator StringBl(Brand<T, BRAND> value) { return value.ToStringBl(); }

    /// <summary>
    /// Convert a Bl value of a sub-type to a branded Bl value of this type.
    /// </summary>
    /// <typeparam name="S">Type of the Bl value.</typeparam>
    /// <param name="value">Bl value to be coerced.</param>
    /// <returns>Branded coerced Bl value.</returns>
    public static BRAND UpCast<S>(Expr<S> value) where S : T {
      return ToBrand(new UpCastExpr<S, T>(value));
    }
    public static BRAND ExplicitConvert<S>(Expr<S> value) {
      return ToBrand(value.ExplicitConvert<T>());
    }

    /// <summary>
    /// Is the underlying value of this Bl value of type S? 
    /// </summary>
    /// <typeparam name="S">Type to test.</typeparam>
    /// <returns>Whether the underlying value is of type S.</returns>
    public BoolBl Is<S>() where S : T {
      return Underlying.Map<bool>(t => t is S);
    }

    protected static readonly Operator<T, T, bool> EqualOp = new Operator<T, T, bool>(Markers.EqualMarker) {
      Apply = (x, y) => {
        var ret = x.Equals(y);
        return ret;
      }
    };
    protected static readonly Operator<T, T, bool> NotEqualOp = new Operator<T, T, bool>(Markers.NotEqualMarker) {
      Apply = (x, y) => {
        return !x.Equals(y);
      }
    };
    public static BoolBl operator ==(Brand<T, BRAND> arg0, BRAND arg1) {
      return (EqualOp.Make(arg0, arg1));
    }
    public static BoolBl operator !=(Brand<T, BRAND> arg0, BRAND arg1) {
      return (NotEqualOp.Make(arg0, arg1));
    }
    public static BoolBl operator ==(T arg0, Brand<T, BRAND> arg1) {
      return (EqualOp.Make(Operations.Make(arg0), arg1));
    }
    public static BoolBl operator !=(T arg0, Brand<T, BRAND> arg1) {
      return (NotEqualOp.Make(Operations.Make(arg0), arg1));
    }
    public override int GetHashCode() {
      return Underlying.GetHashCode();
    }
    public override bool Equals(object obj) {
      if (obj is Brand<T, BRAND>) {
        return Underlying.Equals(((Brand<T, BRAND>)obj).Underlying);
      }
      return base.Equals(obj);
    }

    /// <summary>
    /// to visit the element in array with specified index in the pixel shader, instead of the way values[index]
    /// </summary>
    /// <param name="Index">the index of this element in array</param>
    /// <param name="Values">the array to visit</param>
    /// <returns></returns>
    public static BRAND Table(IntBl Index, params BRAND[] Values) {
      return Values.Table(Index);
    }
    public static BRAND Table(IntBl Index, params T[] Values) {
      BRAND[] Values0 = new BRAND[Values.Length];
      for (int i = 0; i < Values.Length; i++) {
        Values0[i] = ToBrand(new Constant<T>(Values[i]));
      }

      return Values0.Table(Index);
    }
  }
  public partial interface BaseCoreValue<T> {

  }
  /// <summary>
  /// A branded Bl value that adds additional intrinsic operations.
  /// </summary>
  /// <typeparam name="T">Type of the underlying core language value.</typeparam>
  /// <typeparam name="SELF">Branded type of this Bl value.</typeparam>
  public abstract partial class CoreBl<T, BRAND> : Brand<T, BRAND>, BaseCoreValue<T> where BRAND : CoreBl<T, BRAND> {
    public CoreBl(Expr<T> Underlying) : base(Underlying) { }
    public abstract BRAND LerpX(BRAND to, DoubleBl t);
  }
  /// <summary>
  /// Bl wrapper around object.
  /// </summary>
  public partial class ObjectBl : Brand<object, ObjectBl> {
    public ObjectBl(Expr<object> Underlying) : base(Underlying) { }
    public static implicit operator ObjectBl(Expr<object> s) { return new ObjectBl(s); }
    public static implicit operator ObjectBl(StringBl s) { return UpCast<string>(s); }
    public static implicit operator ObjectBl(string s) { return s.Bl(); }

    static ObjectBl() {
      Register(v => v);
    }
    /// <summary>
    /// Convert a Bl value of a sub-type to a branded Bl value of this type.
    /// </summary>
    /// <typeparam name="S">Type of the Bl value.</typeparam>
    /// <param name="value">Bl value to be coerced.</param>
    /// <returns>Branded coerced Bl value.</returns>
    /// <remarks>Method repeated here so ObjectBl initialization occurs properly.</remarks>
    public static new ObjectBl UpCast<T>(Expr<T> t) {
      return Brand<object, ObjectBl>.UpCast<T>(t);
    }
  }

  /// <summary>
  /// Bl wrapper around string.
  /// </summary>
  public partial class StringBl : Brand<string, StringBl> {
    public StringBl(Expr<string> Underlying) : base(Underlying) { }
    public static readonly AssociativeOperator<string, string> Plus = new AssociativeOperator<string, string>(Markers.PlusMarker) { };
    public static implicit operator StringBl(Expr<string> s) { return new StringBl(s); }
    public static implicit operator StringBl(string s) { return new Constant<string>(s); }
    public static StringBl operator +(StringBl op0, StringBl op1) {
      return Plus.Make(op0, op1);
    }
    public static implicit operator StringBl(int s) { return s.Bl(); }
    public static implicit operator StringBl(double s) { return s.Bl(); }
    public static implicit operator StringBl(bool s) { return s.Bl(); }


    static StringBl() {
      Plus.Apply = (a, b) => a + b;
      var Concat = typeof(string).GetMethod("Concat", new Type[] { typeof(string), typeof(string) });
      Plus.Linq = (a, b) => linq.Expression.Call(Concat, a, b);

      Register(v => v);
    }
  }

  public abstract partial class AddBl<T, BRAND> : CoreBl<T, BRAND> where BRAND : AddBl<T, BRAND> {
    public AddBl(Expr<T> Underlying) : base(Underlying) { }
    public static implicit operator AddBl<T, BRAND>(BRAND v) { return (AddBl<T, BRAND>)v; }
    protected static readonly AssociativeOperator<T, T> Plus = new AssociativeOperator<T, T>(Markers.PlusMarker) { };
    protected static readonly AssociativeOperator<T, T> Minus = new AssociativeOperator<T, T>(Markers.MinusMarker) { };
    static AddBl() {
      Plus.Inverse0 = Minus.Make;
      Minus.Inverse0 = Plus.Make;
    }
    public static BRAND operator +(AddBl<T, BRAND> op0, BRAND op1) {
      Expr<T> result = Plus.Make(op0, op1);
      return ToBrand(result);
    }
    public static BRAND operator -(AddBl<T, BRAND> op0, BRAND op1) {
      Expr<T> result = Minus.Make(op0, op1);
      return ToBrand(result);
    }
    public static BRAND operator +(T op0, AddBl<T, BRAND> op1) {
      Expr<T> result = Plus.Make(Operations.Make(op0), op1);
      return ToBrand(result);
    }
    public static BRAND operator -(T op0, AddBl<T, BRAND> op1) {
      Expr<T> result = Minus.Make(Operations.Make(op0), op1);
      return ToBrand(result);
    }
    protected static readonly Operator<T, T, T, T> RestrictOp = new Operator<T, T, T, T>(Markers.RestrictMarker) {
      Expand = (a,b,c) => a,
      Apply = (target, min, max) => target, // a no-op, will clamp the other side.
      Inverse0 = (result, min, max) => ClampOp.Make(result, min, max)
    };
    protected static readonly Operator<T, T, T, T> ClampOp = new Operator<T, T, T, T>(Markers.ClampMarker) {
      Inverse0 = (result, min, max) => RestrictOp.Make(result, min, max)
    };

    /// <summary>
    /// Clamp this value between minimum and maximum values.
    /// </summary>
    /// <param name="min">minimum value of clamp.</param>
    /// <param name="max">maximum value of clamp.</param>
    /// <returns>Clamped value that is no smaller than min and no greater than max.</returns>
    public BRAND Clamp(BRAND min, BRAND max) {
      return ToBrand(ClampOp.Make(this, min, max));
    }

    /// <summary>
    /// Inverse of Clamp. x.Restrict(y,z).Bind = a is equal to x.Bind = a.Restrict(y,z).
    /// </summary>
    /// <param name="min">minimum value of clamp.</param>
    /// <param name="max">maximum value of clamp.</param>
    /// <returns>This value that inverts into a Clamp.</returns>
    public BRAND Restrict(BRAND min, BRAND max) {
      return ToBrand(RestrictOp.Make(this, min, max));
    }

    public BRAND Restrict(Func<BRAND,BRAND> F) {
      var RestrictOp = new Operator<T, T>(Markers.RestrictMarker) {
        Expand = (a) => a,
        Apply = (target) => target, // a no-op, will clamp the other side.
        Inverse = (result) => F(ToBrand(result)).Underlying,
      };
      return ToBrand(RestrictOp.Make(this));
    }


  }

  public abstract partial class MultXBl<T, BRAND> : AddBl<T, BRAND> where BRAND : MultXBl<T, BRAND> {
    public static implicit operator MultXBl<T, BRAND>(BRAND v) { return (MultXBl<T, BRAND>)v; }
    public MultXBl(Expr<T> Underlying) : base(Underlying) { }
    protected static readonly Operator<T, double, T> MultiplyX = new Operator<T, double, T>(Markers.MultiplyMarker) { };
    protected static readonly Operator<T, double, T> DivideX = new Operator<T, double, T>(Markers.DivideMarker) { };
    static MultXBl() {
      MultiplyX.Inverse0 = DivideX.Make;
      DivideX.Inverse0 = MultiplyX.Make;
    }
    protected static BRAND Lerp(DoubleBl lerp0, BRAND from0, BRAND to0) {
      return from0 + (to0 - from0) * (lerp0);
    }
    public override BRAND LerpX(BRAND to, DoubleBl t) {
      return Lerp(t, this, to);
    }

    public static BRAND operator *(MultXBl<T, BRAND> op0, DoubleBl op1) {
      Expr<T> result = MultiplyX.Make(op0, op1);
      return ToBrand(result);
    }
    public static BRAND operator /(MultXBl<T, BRAND> op0, DoubleBl op1) {
      Expr<T> result = DivideX.Make(op0, op1);
      return ToBrand(result);
    }
  }
  public abstract partial class MultBlValue<T, SELF> : MultXBl<T, SELF> where SELF : MultBlValue<T, SELF> {
    public static implicit operator MultBlValue<T, SELF>(SELF v) { return (MultBlValue<T, SELF>)v; }
    public MultBlValue(Expr<T> Underlying) : base(Underlying) { }
    protected static readonly AssociativeOperator<T, T> Multiply = new AssociativeOperator<T, T>(Markers.MultiplyMarker) { };
    protected static readonly Operator<T, T, T> Divide = new Operator<T, T, T>(Markers.DivideMarker) { };
    static MultBlValue() {
      Multiply.Inverse0 = Divide.Make;
      Divide.Inverse0 = Multiply.Make;
      Divide.Inverse1 = (x, y) => Divide.Make(y, x);
    }
    public static SELF operator *(MultBlValue<T, SELF> op0, SELF op1) {
      Expr<T> result = Multiply.Make(op0, op1);
      return ToBrand(result);
    }
    public static SELF operator /(MultBlValue<T, SELF> op0, SELF op1) {
      Expr<T> result = Divide.Make(op0, op1);
      return ToBrand(result);
    }
    public static SELF operator *(T op0, MultBlValue<T, SELF> op1) {
      Expr<T> result = Multiply.Make(Operations.Make(op0), op1);
      return ToBrand(result);
    }
    public static SELF operator /(T op0, MultBlValue<T, SELF> op1) {
      Expr<T> result = Divide.Make(Operations.Make(op0), op1);
      return ToBrand(result);
    }
  }
  /// <summary>
  /// Internal class used to help express tuple-like Bl values.
  /// </summary>
  /// <typeparam name="T"></typeparam>
  /// <typeparam name="SELF"></typeparam>
  public abstract partial class ArityInfo<T, ARITY> where ARITY : ArityInfo<T, ARITY>, new() {
    public static readonly ARITY Instance = new ARITY();
    public Expr<double> Access0(Expr<T> value, int idx) {
      if (value is ArityExpr) return ((ArityExpr)value).Values[idx];
      else return Access(value, idx);
    }
    public abstract string[] AccessorNames { get; }

    public abstract Expr<double> Access(Expr<T> value, int idx);
    public abstract int Arity { get; }
    public abstract double[] ToArray(T t);
    public DoubleBl[] ToArray(Expr<T> t) {
      var ret = new DoubleBl[Arity];
      for (int i = 0; i < Arity; i++)
        ret[i] = Access(t, i);
      return ret;
    }
    public abstract T ToT(double[] values);
    public Expr<T> ToT(DoubleBl[] values) {
      Expr<double>[] values0 = new Expr<double>[values.Length];
      for (int i = 0; i < values.Length; i++)
        values0[i] = values[i];
      return ArityExpr.Make(values0); 
    }
    public T Doit(T t0, T t1, Func<double, double, double> f) {
      var op0 = ToArray(t0);
      var op1 = ToArray(t1);
      var ret = new double[Arity];
      for (int i = 0; i < Arity; i++) ret[i] = f(op0[i], op1[i]);
      return ToT(ret);
    }
    public class ArityExpr : Expr<T> {
      public readonly IList<Expr<double>> Values;

      public static Expr<T> Make(params Expr<double>[] values) {
        var allConstant = true;
        foreach (var v in values)
          allConstant = allConstant && v is Constant<double>;
        if (allConstant) {
          double[] d = new double[values.Length];
          for (int i = 0; i < values.Length; i++)
            d[i] = ((Constant<double>)values[i]).Value;
          return new Constant<T>(Instance.ToT(d));
        }
        return new ArityExpr(values);
      }

      private ArityExpr(params Expr<double>[] values) {

        this.Values = values;
      }
      public override int GetHashCode() {
        int hc = 0;
        foreach (var v in Values) hc += v.GetHashCode();
        return hc;
      }
      public override bool Equals(object obj) {
        if (!(obj is ArityExpr)) return false;
        var value = (ArityExpr)obj;
        for (int i = 0; i < Values.Count; i++)
          if (!Values[i].Equals(value.Values[i])) return false;
        return true;
      }

      public override Eval<EVAL>.Info<T> Eval<EVAL>(Eval<EVAL> txt) { return txt.ArityX(this); }
      public override bool Solve(Assign P, Expr<T> other) {
        if (base.Solve(P, other)) return true;
        else {
          var allFalse = true;
          var allTrue = true;
          for (int i = 0; i < Instance.Arity; i++) {
            var r = Values[i].Solve(P.Copy(), Instance.Access0(other, i));
            allFalse = allFalse && !r;
            allTrue = allTrue && r;
          }
          if (allFalse) return false;
          if (allTrue) return true;
          //return false;
          throw new NotSupportedException();
        }
      }
      public override string ToString() {
        var ret = "[";
        for (int i = 0; i < Values.Count; i++) {
          if (i != 0) ret = ret + ", ";
          ret = ret + Values[i].ToString();
        }
        return ret;
      }
    }
    public virtual Func<T, T, T> F(Func<double, double, double> f) {
      return (x, y) => Doit(x, y, (xx, yy) => f(xx, yy));
    }

    public T Doit(T t0, Func<double, double> f) {
      var op0 = ToArray(t0);
      var ret = new double[Arity];
      for (int i = 0; i < Arity; i++) ret[i] = f(op0[i]);
      return ToT(ret);
    }

    public T Doit(T t0, T t1, T t2, Func<double, double, double, double> f) {
      var op0 = ToArray(t0);
      var op1 = ToArray(t1);
      var op2 = ToArray(t2);
      var ret = new double[Arity];
      for (int i = 0; i < Arity; i++) ret[i] = f(op0[i], op1[i], op2[i]);
      return ToT(ret);
    }
    public Expr<T> Doit(Expr<T> t0, Expr<T> t1, Expr<T> t2, Func<DoubleBl, DoubleBl, DoubleBl, DoubleBl> f) {
      var op0 = ToArray(t0);
      var op1 = ToArray(t1);
      var op2 = ToArray(t2);
      var ret = new DoubleBl[Arity];
      for (int i = 0; i < Arity; i++) ret[i] = f(op0[i], op1[i], op2[i]);
      return ToT(ret);
    }

    public virtual Func<T, T> F(Func<double, double> f) {
      return (x) => Doit(x, (xx) => f(xx));
    }
    public virtual Func<T, double, T> F0(Func<double, double, double> f) {
      return (x, y) => Doit(x, (xx) => f(xx, y));
    }
    public virtual Func<T, T, T, T> F0(Func<double, double, double, double> f) {
      return (x, y, z) => Doit(x, y, z, (xx, yy, zz) => f(xx, yy, zz));
    }
    public virtual Func<Expr<T>, Expr<T>, Expr<T>, Expr<T>> F0E(Func<DoubleBl, DoubleBl, DoubleBl, DoubleBl> f) {
      return (x, y, z) => Doit(x, y, z, (xx, yy, zz) => f(xx, yy, zz));
    }
    public Func<T, T> Map(Func<double, double> f) {
      return t => {
        var d = ToArray(t);
        var res = new double[Arity];
        for (int i = 0; i < res.Length; i++)
          res[i] = f(d[i]);
        return ToT(res);
      };
    }
    public Func<T, S> G<S>(S init, Func<S, double, S> f, Func<S, S> g) {
      return t => {
        var d = ToArray(t);
        var s = init;
        foreach (var ds in d) s = f(s, ds);
        return g(s);
      };
    }
    public Func<T, S> G<S>(Func<S, double, S> f, Func<S, S> g) {
      return G(default(S), f, g);
    }
    public Func<T, S> G<S>(Func<S, double, S> f) {
      return G(f, s => s);
    }
  }
  public interface TupleBl<T> : BaseBrandT<T> { }

  public abstract partial class TupleBl<T, BRAND, ARITY> : MultXBl<T, BRAND>, TupleBl<T>
    where BRAND : TupleBl<T, BRAND, ARITY>
    where ARITY : ArityInfo<T, ARITY>, new() {
    public static implicit operator TupleBl<T, BRAND, ARITY>(BRAND v) { return (TupleBl<T, BRAND, ARITY>)v; }
    public static ARITY Arity {
      get { return ArityInfo<T, ARITY>.Instance; }
    }

    // we inherit all operators in double to double.
    protected static readonly Operator<T, T, T> MaxOp = new Operator<T, T, T>(Markers.MaxMarker) {
      Apply = Arity.F((a, b) => Math.Max(a, b)),
    };
    protected static readonly Operator<T, T, T> MinOp = new Operator<T, T, T>(Markers.MinMarker) {
      Apply = Arity.F((a, b) => Math.Min(a, b)),
    };
    protected static readonly Operator<T, T> AbsOp = new Operator<T, T>(Markers.AbsMarker) {
      Apply = Arity.F((a) => Math.Abs(a))
    };
    protected static readonly Operator<T, T> RoundOp = new Operator<T, T>(Markers.RoundMarker) {
      Apply = Arity.F((a) => Math.Round(a)),
      Inverse = (x) => x,
    };
    protected static readonly Operator<T, T> FloorOp = new Operator<T, T>(Markers.FloorMarker) {
      Apply = Arity.F((a) => Math.Floor(a)),
      Inverse = (x) => x,
    };
    protected static readonly Operator<T, T> LogOp = new Operator<T, T>(Markers.LogMarker) {
      Apply = Arity.F(( a ) => Math.Log(a))
    };
    protected static readonly Operator<T, T> Log10Op = new Operator<T, T>(Markers.Log10Marker) {
      Apply = Arity.F(( a ) => Math.Log10(a))
    };
    protected static readonly Operator<T, T> CeilingOp = new Operator<T, T>(Markers.CeilingMarker) {
      Apply = Arity.F((a) => Math.Ceiling(a)),
      Inverse = (x) => x,
    };
    protected virtual BRAND Unary(Operator<T, T> opA, Operator<double,double> opB) {
      Expr<double>[] d = new Expr<double>[Arity.Arity];
      for (int i = 0; i < Arity.Arity; i++) {
        d[i] = opB.Make(this[i]);
      }
      return ToBrand(ArityInfo<T, ARITY>.ArityExpr.Make(d));
    }
    protected virtual BRAND Binary(BRAND arg, Operator<T, T, T> opA, Operator<double, double, double> opB) {
      Expr<double>[] d = new Expr<double>[Arity.Arity];
      for (int i = 0; i < Arity.Arity; i++) {
        d[i] = opB.Make(this[i], arg[i]);
      }
      return ToBrand(ArityInfo<T, ARITY>.ArityExpr.Make(d));
    }
    /// <summary>
    /// Clamp components between 0 and 1.
    /// </summary>
    public BRAND Saturate {
      get {
        Expr<double>[] d = new Expr<double>[Arity.Arity];
        for (int i = 0; i < Arity.Arity; i++) {
          d[i] = this[i].Clamp(0d,1d);
        }
        return ToBrand(ArityInfo<T, ARITY>.ArityExpr.Make(d));
      }
    }
    /// <summary>
    /// Returns the absolute value of a number.
    /// </summary>
    /// <returns>
    /// A number, x, such that 0 ≤ x ≤System.typeof(this).MaxValue.
    /// </returns>
    public BRAND Abs {
      get { return Unary(AbsOp, DoubleBl.AbsOp); }
    }

    public static implicit operator TupleBl<T,BRAND,ARITY>(Random r) {
      Expr<double>[] d = new Expr<double>[Arity.Arity];
      for (int i = 0; i < Arity.Arity; i++) {
        d[i] = Expr<double>.FromFunc(() => r.NextDouble());
      }
      return ToBrand(ArityInfo<T, ARITY>.ArityExpr.Make(d));
    }

    /// <summary>
    /// Apply restitution to a old/now value pair where this is the old value.
    /// </summary>
    /// <param name="now">The current value of the property being restituted.</param>
    /// <param name="min">A minimum value for the property being restituted.</param>
    /// <param name="max">A maximum value for the property being restituted.</param>
    /// <returns>An updated old value for the property being restitued. 
    ///          Swap old and now compents if the now value is out of bounds</returns>
    public BRAND Restitution(BRAND now, BRAND min, BRAND max) {
      Expr<double>[] results = new Expr<double>[Arity.Arity];
      for (int i = 0; i < Arity.Arity; i++) {
        //results[i] = (now[i] < min[i]).Condition(now[i], (now[i] > max[i]).Condition(now[i], this[i]));

        results[i] = (now[i] < min[i] | now[i] > max[i]).Condition(now[i], this[i]);
      }
      return ToBrand(ArityInfo<T, ARITY>.ArityExpr.Make(results));
    }
    /// <summary>
    /// Apply both restitution and clamp to specified property.
    /// </summary>
    /// <param name="min">A minimum value for the property being clamped/restituted.</param>
    /// <param name="max">A maximum value for the property being clamped/restituted.</param>
    public void ClampWithRestitution(BRAND min, BRAND max) {
      this.Old = this.Old.Restitution(this, min, max);
      this.Bind = this.Clamp(min, max);
    }
    /// <summary>
    /// Apply both restitution and clamp to specified property.
    /// </summary>
    /// <param name="strength">Strength of clamp/restitution constraints.</param>
    /// <param name="min">A minimum value for the property being clamped/restituted.</param>
    /// <param name="max">A maximum value for the property being clamped/restituted.</param>
    public void ClampWithRestitution(DoubleBl strength, BRAND min, BRAND max) {
      this.Old.Relax[strength] = this.Old.Restitution(this, min, max);
      this.Relax[strength] = this.Clamp(min, max);
    }



    /// <summary>
    /// Rounds a value to the nearest integer.
    /// </summary>
    /// <returns>
    /// The integer nearest this. If the fractional component of this is halfway between
    ///     two integers, one of which is even and the other odd, then the even number
    ///     is returned.
    /// </returns>
    public BRAND Round {
      get { return Unary(RoundOp, DoubleBl.RoundOp); }
    }

    /// <summary>
    /// Round the number then be devided by the param d
    /// </summary>
    /// <param name="d"></param>
    /// <returns></returns>
    public BRAND RoundN(DoubleBl d) { return (this * d).Round / d; }

    /// <summary>
    /// Returns the largest integer less than or equal to the specified number.
    /// </summary>
    /// <returns>
    /// The largest integer less than or equal to this. If this is equal to System.Double.NaN,
    ///     System.Double.NegativeInfinity, or System.Double.PositiveInfinity, that value
    ///     is returned.
    /// </returns>
    public BRAND Floor {
      get { return Unary(FloorOp, DoubleBl.FloorOp); }
    }
    /// <summary>
    /// Returns the natural (base e) logarithm of a specified number.
    /// </summary>
    /// <returns>
    /// Returns Positive The natural logarithm of this; that is, ln this, or log
    ///     edZero System.Double.NegativeInfinityNegative System.Double.NaN. If this is equal
    ///     to System.Double.NaN, returns System.Double.NaN. If this is equal to System.Double.PositiveInfinity,
    ///     returns System.Double.PositiveInfinity.
    /// </returns>
    public BRAND Log {
      get { return Unary(LogOp, DoubleBl.LogOp); }
    }
    /// <summary>
    /// Returns the base 10 logarithm of a specified number.
    /// </summary>
    /// <returns>
    /// Sign of dReturns Positive The base 10 log of this; that is, log 10this. Zero System.Double.NegativeInfinityNegative
    ///     System.Double.NaN, If this is equal to System.Double.NaN, this method returns
    ///     System.Double.NaN. If this is equal to System.Double.PositiveInfinity, this
    ///     method returns System.Double.PositiveInfinity.
    /// </returns>
    public BRAND Log10 {
      get { return Unary(Log10Op, DoubleBl.Log10Op); }
    }
    /// <summary>
    /// Returns the smallest integer which is greater than or equal to the specified number
    /// </summary>
    /// <returns>
    ///      The smallest integer greater than or equal to a. If a is equal to System.Double.NaN,
    ///     System.Double.NegativeInfinity, or System.Double.PositiveInfinity, that value
    ///     is returned.
    /// </returns>
    public BRAND Ceiling {
      get { return Unary(CeilingOp, DoubleBl.CeilingOp); }
    }
    /// <summary>
    /// Returns the larger of two numbers.
    /// </summary>
    /// <param name="other">the other number to compare with this</param>
    /// <returns></returns>
    public BRAND Max(BRAND other) { return Binary(other, MaxOp, DoubleBl.MaxOp); }
    /// <summary>
    /// Returns the smaller of two numbers.
    /// </summary>
    /// <param name="other">the other number to compare with this</param>
    /// <returns></returns>
    public BRAND Min(BRAND other) { return Binary(other, MinOp, DoubleBl.MinOp); }
    /// <summary>
    /// Will replace this Bl value components with other Bl value components if they are NaN.
    /// </summary>
    /// <param name="other">Other value to replace NaN components with.</param>
    /// <returns>Cleaned value.</returns>
    public BRAND Clean(BRAND other) {
      Expr<double>[] result = new Expr<double>[Arity.Arity];
      for (int i = 0; i < result.Length; i++) {
        result[i] = this[i].IsNaN.Condition(other[i], this[i]).Check("NAN: " + other[i] + " " + this[i]);
      }
      return ToBrand(ArityInfo<T, ARITY>.ArityExpr.Make(result));
    }
    /// <summary>
    /// For debugging only. Will cause an assertion when NaN is detected in a value's components.
    /// </summary>
    /// <param name="msg">Message to use in the assertion.</param>
    /// <returns></returns>
    public virtual BRAND Check(StringBl msg) {
      Expr<double>[] result = new Expr<double>[Arity.Arity];
      for (int i = 0; i < result.Length; i++) {
        result[i] = this[i].Check(msg);
      }
      return ToBrand(ArityInfo<T, ARITY>.ArityExpr.Make(result));
    }
    /*
    protected class AccessOp : Operator<T, double> {
      public AccessOp(int idx)
        : base(new Markers.AccessMarker(idx)) {
        Apply = (x) => Arity.ToArray(x)[((Markers.AccessMarker)Marker).Idx];
      }
    }
     */
    public TupleBl(Expr<T> Underlying) : base(Underlying) { }
    static TupleBl() {
      Accessors = new Operator<T, double>[Arity.Arity];
      for (int i = 0; i < Arity.Arity; i++) {
        var ii = i;
        Accessors[i] = new Operator<T, double>(new Markers.UnaryAccessOperator(Arity.AccessorNames[ii])) {
          Apply = t => Arity.ToArray(t)[ii],
          Expand = t => {
            if (t is ArityInfo<T, ARITY>.ArityExpr) {
              return ((ArityInfo<T, ARITY>.ArityExpr)t).Values[ii];
            }
            return null;
          },
        };
      }
      if (Plus.Apply == null) 
        Plus.Apply = Arity.F((x, y) => x + y);
      if (Minus.Apply == null) 
        Minus.Apply = Arity.F((x, y) => x - y);
      if (MultiplyX.Apply == null)
        MultiplyX.Apply = Arity.F0((x, y) => x * y);
      if (DivideX.Apply == null)
        DivideX.Apply = Arity.F0((x, y) => x / y);
      if (ClampOp.Apply == null)
        ClampOp.Apply = Arity.F0((r0, min, max) => r0.Clamp(min, max));

      ClampOp.Expand = Arity.F0E((r0, min, max) => r0.Clamp(min, max));
    }
    protected static readonly Operator<T, double>[] Accessors;

    /// <summary>
    /// Return component of this tuple.
    /// </summary>
    /// <param name="idx">Index of component to access.</param>
    /// <returns>Double component of tuple at specified index.</returns>
    public DoubleBl this[int idx] {
      get {
        if (Underlying is ArityInfo<T, ARITY>.ArityExpr) {
          return ((ArityInfo<T, ARITY>.ArityExpr)Underlying).Values[idx];
        }
        return Accessors[idx].Make(this);
      }
      set {
        this[idx].Bind = value;
      }
    }
  }
  public abstract partial class RealTupleBl<T, BRAND, ARITY> : TupleBl<T, BRAND, ARITY>
    where BRAND : TupleBl<T, BRAND, ARITY>
    where ARITY : ArityInfo<T, ARITY>, new() {
    public RealTupleBl(Expr<T> Underlying) : base(Underlying) { }
    static RealTupleBl() {

      Plus.Linq = (e1, e2) =>
        linq.Expression.Add(e1, linq.Expression.Convert(e2, VectorType));
      Plus.AsText = (e1, e2) => "(" + e1 + " + " + vcast(e2) + ")";
      Plus.Apply = Arity.F((aa, bb) => aa + bb);

        

      Minus.Linq = (e1, e2) =>
        linq.Expression.Subtract(e1, linq.Expression.Convert(e2, VectorType));
      Minus.AsText = (e1, e2) => "(" + e1 + " - " + vcast(e2) + ")";
      Minus.Apply = Arity.F((aa, bb) => aa - bb);
      MultiplyX.Linq = (e1, e2) =>
        linq.Expression.Convert(linq.Expression.Multiply(linq.Expression.Convert(e1, VectorType), e2), typeof(T));
      MultiplyX.AsText = (e1, e2) => tcast(vcast(e1) + " * " + (e2));
      MultiplyX.Apply = (a,b) => Arity.Map((aa) => aa * b)(a);

      DivideX.Linq = (e1, e2) =>
        linq.Expression.Convert(linq.Expression.Divide(linq.Expression.Convert(e1, VectorType), e2), typeof(T));
      DivideX.AsText = (e1, e2) => tcast(vcast(e1) + " / " + (e2));
      DivideX.Apply = (a, b) => Arity.Map((aa) => aa / b)(a);

    }
    protected static Type VectorType = null; //typeof(Vector);
    protected static string vcast(string str) { return "((" + VectorType.FullName + ") (" + str + "))"; }
    protected static string tcast(string str) { return "((" + typeof(T).FullName + ") (" + str + "))"; }

    protected static readonly AssociativeOperator<T> Negate = new AssociativeOperator<T>(Markers.MinusMarker) {
      Apply = Arity.F(x => -x),
    };
    protected static readonly Operator<T, double> LengthOp = new Operator<T, double>(Markers.LengthMarker) {
      Apply = Arity.G<double>((s, d) => s + d * d, s => Math.Sqrt(s)),
      Linq = (e) => 
        (linq.Expression.Property(linq.Expression.ConvertChecked(e, VectorType), "Length")),
      AsText = (e) => vcast(e) + ".Length",
    };
    protected static readonly Operator<T, double> LengthSquaredOp = new Operator<T, double>(new OperatorMarker("LengthSquared")) {
      Apply = Arity.G<double>((s, d) => s + d * d, s => (s)),
      Linq = (e) =>
        (linq.Expression.Property(linq.Expression.ConvertChecked(e, VectorType), "LengthSquared")),
      AsText = (e) => vcast(e) + ".LengthSquared",
    };

    protected static readonly Operator<T, bool> IsNanOp = new Operator<T, bool>(Markers.IsNanMarker) {
      Apply = Arity.G<bool>(false,
                            (s, d) => s || double.IsNaN(d),
                            s => s),
    };
    protected static readonly Operator<T, bool> IsInfinityOp = new Operator<T, bool>(Markers.IsInfMarker) {
      Apply = Arity.G<bool>(false,
                            (s, d) => s || double.IsInfinity(d),
                            s => s),
    };
    protected static readonly Operator<T, T> SquareOp = new Operator<T, T>(Markers.SquareMarker) {
      Apply = Arity.F((a) => a * a),
      Inverse = a => SqrtOp.Make(a),
    };
    protected static readonly Operator<T, T> SqrtOp = new Operator<T, T>(Markers.SqrtMarker) {
      Apply = Arity.F((a) => Math.Sqrt(a)),
      Inverse = a => SquareOp.Make(a),
    };
    protected static readonly Operator<T, double, T> PowOp = new Operator<T, double, T>(Markers.PowMarker) {
      Apply = Arity.F0((a, b) => Math.Pow(a, b)),
      Inverse0 = (result, pow) => PowOp.Make(result, 1d / pow.Bl())
    };
    public static BRAND operator -(RealTupleBl<T, BRAND, ARITY> d) {
      return ToBrand(Negate.Make(d));
    }

    /// <summary>
    /// Initilize each element of this tuple to assigned double. 
    /// </summary>
    public double Scalar {
      set {
        var d = new double[Arity.Arity];
        for (int i = 0; i < d.Length; i++) d[i] = value;
        this.Bind = ToBrand(new Constant<T>(Arity.ToT(d)));
      }
    }
    /// <summary>
    /// Vector length of this tuple (defined as the square root of the sum of its components squared).
    /// </summary>
    public virtual DoubleBl Length {
      get { 
        return (LengthOp.Make(Underlying)); }
    }

    /// <summary>
    /// Square of the tuple's vector length. More efficient to compute than Length.
    /// </summary>
    public virtual DoubleBl LengthSquared {
      get {
        return (LengthSquaredOp.Make(Underlying));
      }
    }

    /// <summary>
    ///  Returns a value indicating whether the specified number evaluates to a value
    ///     that is not a number (System.Double.NaN).
    /// </summary>
    /// <returns>
    /// true if d evaluates to System.Double.NaN; otherwise, false.
    /// </returns>
    public BoolBl IsNaN {
      get { return IsNanOp.Make(this); }
    }
    /// <summary>
    /// Returns a value indicating whether the specified number evaluates to negative
    ///     or positive infinity
    /// </summary>
    /// <returns>
    /// true if d evaluates to System.Double.PositiveInfinity or System.Double.NegativeInfinity;
    ///     otherwise, false.
    ///</returns>
    public BoolBl IsInfinity {
      get { return IsInfinityOp.Make(this); }
    }
    /// <summary>
    /// Returns the square of a specified number
    /// </summary>
    public BRAND Square() {
      return ToBrand(SquareOp.Make(this)); 
    }
    /// <summary>
    /// Returns a specified number(this) raised to the specified power.
    /// </summary>
    /// <param name="e">A double-precision floating-point number extended by Bl that specifies a power</param>
    /// <returns>
    /// The number x raised to the power y.The following table indicates the return
    ///     value when various values or ranges of values are specified for the x and
    ///     y parameters. For more information, see System.Double.PositiveInfinity, System.Double.NegativeInfinity,
    ///     and System.Double.NaN.Parameters Return Value x or y = NaN NaN x = Any value
    ///     except NaN; y = 0 1 x = NegativeInfinity; y &lt; 0 0 x = NegativeInfinity; y
    ///     is a positive odd integer NegativeInfinity x = NegativeInfinity; y is positive
    ///     but not an odd integer PositiveInfinity x &lt; 0 but not NegativeInfinity; y
    ///     is not an integer, NegativeInfinity, or PositiveInfinityNaN x = -1; y = NegativeInfinity
    ///     or PositiveInfinity NaN -1 &lt; x &lt; 1; y = NegativeInfinity PositiveInfinity
    ///     -1 &lt; x &lt; 1; y = PositiveInfinity 0 x &lt; -1 or x &gt; 1; y = NegativeInfinity
    ///     0 x &lt; -1 or x &gt; 1; y = PositiveInfinity PositiveInfinity x = 0; y &lt; 0 PositiveInfinity
    ///     x = 0; y &gt; 0 0 x = 1; y is any value except NaN 1 x = PositiveInfinity; y
    ///    &lt; 0 0 x = PositiveInfinity; y &gt; 0 PositiveInfinity
    ///</returns>
    public virtual BRAND Pow(DoubleBl e) {
      if (e.Underlying is Constant<double>) {
        var d = ((Constant<double>)e.Underlying).Value;
        if (d == 1.0) return this;
        if (d == 0.0) {
          double[] dd = new double[Arity.Arity];
          for (int i = 0; i < dd.Length; i++) dd[i] = 1d;
          var t = Arity.ToT(dd);
          return ToBrand(new Constant<T>(t));
        }
        if (d == 2.0) {
          return this.Square();
        }
      }
      return ToBrand(PowOp.Make(this, e));
    }
    /// <summary>
    /// Returns the square root of a specified number
    /// </summary>
    public BRAND Sqrt() {
      return ToBrand(SqrtOp.Make(this)); 
    }
  }

  public abstract class ScalarArity<T,BRAND> : ArityInfo<T,BRAND> where BRAND : ScalarArity<T,BRAND>, new() {
    public override int Arity {
      get { return 1; }
    }
    public abstract T ToT(double d);
    public abstract double ToDouble(T t);

    public override double[] ToArray(T t) {
      return new double[] { ToDouble(t) };
    }
    public override T ToT(double[] values) {
      return ToT(values[0]);
    }
  }
  public abstract partial class ScalarBlValue<T, SELF, ARITY> : RealTupleBl<T, SELF, ARITY>
    where SELF : ScalarBlValue<T, SELF, ARITY>
    where ARITY : ArityInfo<T, ARITY>, new() {

    public ScalarBlValue(Expr<T> Underlying) : base(Underlying) { }

  }
  public class DoubleArity : ScalarArity<double, DoubleArity> {
    public override string[] AccessorNames {
      get { 
        return new string[] { "XXX" }; 
      }
    }
    public override double ToDouble(double t) {
      return t; 
    }
    public override double ToT(double d) {
      return d;
    }
    public override Expr<double> Access(Expr<double> value, int idx) {
      return value;
    }
    public override Func<double, double, double> F(Func<double, double, double> f) {
      return f;
    }
    public override Func<double, double> F(Func<double, double> f) {
      return f;
    }
    public override Func<double, double, double, double> F0(Func<double, double, double, double> f) {
      return f;
    }
    public override Func<double, double, double> F0(Func<double, double, double> f) {
      return f;
    }
  }


  /// <summary>
  /// Bl wrapper around double.
  /// </summary>
  public partial class DoubleBl : ScalarBlValue<double, DoubleBl, DoubleArity> {
    public static implicit operator DoubleBl(double d) { return new DoubleBl(Operations.Make(d)); }
    public static implicit operator DoubleBl(int d) { return new DoubleBl(Operations.Make((double)d)); }
    public static implicit operator DoubleBl(float d) { return new DoubleBl(Operations.Make((double)d)); }


    public DoubleBl Atan2(DoubleBl Y) { return RadianAngleBl.ATan2Op.Make(this, Y); }

    private DoubleBl(Expr<double> Underlying) : base(Underlying) { }
    public static implicit operator DoubleBl(Expr<double> v) { return new DoubleBl(v); }
    static DoubleBl() {
      VectorType = typeof(double);
      MultiplyX.Inverse1 = DivideX.Make;
      DivideX.Inverse1 = MultiplyX.Make;
      // length is a no-op, obviously!
      LengthOp.Apply = (l) => l;
      LengthOp.Expand = (v) => v;
      LengthOp.Inverse = (v) => v;
      Register(v => new DoubleBl(v));

      ClampOp.Expand = (d, min, max) => (d.Bl() < min.Bl()).Condition(min, (d.Bl() > max.Bl()).Condition(max, d));

      (Accessors.Length == 1).Assert();
      Accessors[0] = new Operator<double, double>(new OperatorMarker("noop")) {
        Expand = (a) => a,
        Inverse = (a) => a,
      };
      var SignMethod = typeof(Math).GetMethod("Sign", new Type[] { typeof(double) });
      var IsNaNMethod = typeof(double).GetMethod("IsNaN", new Type[] { typeof(double) });
      SignOp.Linq = (a) => {
        var isNaN = linq.Expression.Call(IsNaNMethod, a);
        return linq.Expression.Condition(isNaN, linq.Expression.Constant(double.NaN, typeof(double)), linq.Expression.Convert(linq.Expression.Call(SignMethod, a), typeof(double)));
      };

    }

    /// <summary>
    /// gets this as the length
    /// </summary>
    public override DoubleBl Length {
      get { return this; }
    }

    public static implicit operator DoubleBl(Random r) {
      return Expr<double>.FromFunc(() => r.NextDouble());
    }

    /// <summary>
    /// Gets or sets this as degrees type
    /// </summary>
    public DegreeAngleBl ToDegrees() {
      return DegreeAngleBl.FromDegrees(this);
    }
    /// <summary>
    /// Gets or sets this as radians type
    /// </summary>
    public RadianAngleBl ToRadians() {
      return RadianAngleBl.FromRadians(this);
    }
    /// <summary>
    /// Represents the ratio of the circumference of a circle to its diameter, specified
    ///     by the constant, π.
    /// </summary>
    public RadianAngleBl ToPI() {
        return RadianAngleBl.FromRadians(this * Math.PI);
    }

    protected override DoubleBl Unary(Operator<double, double> opA, Operator<double, double> opB) {
      (opA == opB).Assert();
      return opA.Make(this);
    }
    protected override DoubleBl Binary(DoubleBl arg, Operator<double, double, double> opA, Operator<double, double, double> opB) {
      (opA == opB).Assert();
      return opA.Make(this, arg);
    }

    public static DoubleBl operator &(DoubleBl op0, BoolBl op1) {
      return op1.Condition(op0, 0d);
    }

    protected static readonly Operator<double, double> SignOp = new Operator<double, double>(Markers.SignMarker) {
      Apply = (a) => {
        if (double.IsNaN(a)) return double.NaN;
        else return Math.Sign(a);
      },
    };
    /// <summary>
    ///  Returns a value indicating the sign of a double-precision floating-point
    ///  number. If NaN, returns NaN.
    /// </summary>
    public DoubleBl Sign {
      get { return SignOp.Make(this).Bl(); }
    }
    /// <summary>
    /// Performs a linear interpolation based on the following formula: from + this * (to - from)
    /// </summary>
    /// <param name="from"></param>
    /// <param name="to"></param>
    /// <returns></returns>
    public DoubleBl Lerp(DoubleBl from, DoubleBl to) {
      return DoubleBl.Lerp(this, from, to);
    }
    /// <summary>
    /// Performs a linear interpolation based on the following formula: from + this * (to - from)
    /// </summary>
    /// <param name="from"></param>
    /// <param name="to"></param>
    /// <returns></returns>
    public RadianAngleBl Lerp( RadianAngleBl from, RadianAngleBl to ) {
      return RadianAngleBl.SafeLerp(from, to, this);
    }
    /// <summary>
    /// Performs a linear interpolation based on the following formula: from + this * (to - from)
    /// </summary>
    /// <param name="from"></param>
    /// <param name="to"></param>
    /// <returns></returns>
    public DegreeAngleBl Lerp( DegreeAngleBl from, DegreeAngleBl to ) {
      return DegreeAngleBl.SafeLerp(from, to, this);
    }
    /// <summary>
    /// Performs a linear interpolation based on the following formula: from + this * (to - from)
    /// </summary>
    /// <param name="from"></param>
    /// <param name="to"></param>
    /// <returns></returns>
    public ColorBl Lerp( ColorBl from, ColorBl to ) {
      return ColorBl.Lerp(this, from, to);
    }
    /// <summary>
    /// Performs a linear interpolation based on the following formula: from + this * (to - from)
    /// </summary>
    /// <param name="from"></param>
    /// <param name="to"></param>
    /// <returns></returns>
    public PointBl Lerp( PointBl from, PointBl to ) {
      return PointBl.Lerp(this, from, to);
    }
    /// <summary>
    /// Performs a linear interpolation based on the following formula: from + this * (to - from)
    /// </summary>
    /// <param name="from"></param>
    /// <param name="to"></param>
    /// <returns></returns>
    public Point3DBl Lerp(Point3DBl from, Point3DBl to) {
      return Point3DBl.Lerp(this, from, to);
    }



    public static DoubleBl operator *(double c, DoubleBl d) {
      return (Operations.Make(c)).Bl() * d;
    }
    public static DoubleBl operator /(double c, DoubleBl d) {
      return (Operations.Make(c)).Bl() / d;
    }
    protected static readonly Operator<double, double, bool> GreaterEqualOp = new Operator<double, double, bool>(Markers.GreaterEqualMarker) {
      Apply = (x, y) => x >= y,
    };
    protected static readonly Operator<double, double, bool> LessEqualOp = new Operator<double, double, bool>(Markers.LessEqualMarker) {
      Apply = (x, y) => x <= y,
    };
    protected static readonly Operator<double, double, bool> GreaterOp = new Operator<double, double, bool>(Markers.GreaterMarker) {
      Apply = (x, y) => x > y,
    };
    protected static readonly Operator<double, double, bool> LessOp = new Operator<double, double, bool>(Markers.LessMarker) {
      Apply = (x, y) => x < y,
    };

    protected static readonly Operator<double, double, double> ModOp = new Operator<double, double, double>(Markers.ModMarker) {
      Apply = (x, y) => x % y,
    };
    protected static readonly Operator<double, double> FracOp = new Operator<double, double>(Markers.FracMarker) {
      Apply = (x) => Math.Abs(x % 1d),
    };

    public static DoubleBl operator %(DoubleBl op0, DoubleBl op1) {
      return ModOp.Make(op0, op1).Bl();
    }
    public DoubleBl Frac { get { return FracOp.Make(this); } }

    protected static readonly Operator<double, int> ToIntOp = new Operator<double, int>(Markers.DoubleToInt) {
      Apply = (x) => (int) x,
      Inverse = (x) => (DoubleBl) x.Bl(),
    };
    public static explicit operator IntBl(DoubleBl d) {
      return ToIntOp.Make(d).Bl();
    }


    public static BoolBl operator >=(DoubleBl arg0, DoubleBl arg1) {
      return (GreaterEqualOp.Make(arg0, arg1));
    }
    public static BoolBl operator <=(DoubleBl arg0, DoubleBl arg1) {
      return (LessEqualOp.Make(arg0, arg1));
    }
    public static BoolBl operator >(DoubleBl arg0, DoubleBl arg1) {
      return (GreaterOp.Make(arg0, arg1));
    }
    public static BoolBl operator <(DoubleBl arg0, DoubleBl arg1) {
      return (LessOp.Make(arg0, arg1));
    }
    /// <summary>
    /// Returns a specified number(this) raised to the specified power.
    /// </summary>
    /// <param name="e">A double-precision floating-point number extended by Bl that specifies a power</param>
    /// <returns>
    /// The number x raised to the power y.The following table indicates the return
    ///     value when various values or ranges of values are specified for the x and
    ///     y parameters. For more information, see System.Double.PositiveInfinity, System.Double.NegativeInfinity,
    ///     and System.Double.NaN.Parameters Return Value x or y = NaN NaN x = Any value
    ///     except NaN; y = 0 1 x = NegativeInfinity; y &lt; 0 0 x = NegativeInfinity; y
    ///     is a positive odd integer NegativeInfinity x = NegativeInfinity; y is positive
    ///     but not an odd integer PositiveInfinity x &lt; 0 but not NegativeInfinity; y
    ///     is not an integer, NegativeInfinity, or PositiveInfinityNaN x = -1; y = NegativeInfinity
    ///     or PositiveInfinity NaN -1 &lt; x &lt; 1; y = NegativeInfinity PositiveInfinity
    ///     -1 &lt; x &lt; 1; y = PositiveInfinity 0 x &lt; -1 or x &gt; 1; y = NegativeInfinity
    ///     0 x &lt; -1 or x &gt; 1; y = PositiveInfinity PositiveInfinity x = 0; y &lt; 0 PositiveInfinity
    ///     x = 0; y &gt; 0 0 x = 1; y is any value except NaN 1 x = PositiveInfinity; y
    ///    &lt; 0 0 x = PositiveInfinity; y &gt; 0 PositiveInfinity
    ///</returns>
    public override DoubleBl Pow(DoubleBl v) {
      if (v.Underlying is Constant<double>) {
        double d = ((Constant<double>)v.Underlying).Value;
        if (d == 0) return 1d;
        else if (d == 1) return this;
        else if (d == 2) return Square();
        //else if (d == 3) return this * this * this;
      }
      return base.Pow(v);
    }
    protected static Operator<double, string, double> CheckOp = new Operator<double, string, double>(Markers.CheckNanMarker) {
      Apply = (d, str) => {
        (!double.IsNaN(d)).Assert();
        return d;
      },
      Linq = (d, str) => {
        if (CheckNanInfo == null)
          CheckNanInfo = typeof(DoubleBl).GetMethod("CheckNan", new Type[] { typeof(double), typeof(string) });
        return linq.Expression.Call(CheckNanInfo, d, str);
      },
    };
    public static double CheckNan(double d, string str) {
      (!double.IsNaN(d)).Assert();
      return d;
    }
    private static System.Reflection.MethodInfo CheckNanInfo = null;

    public override DoubleBl Check(StringBl msg) {
      return CheckOp.Make(this, msg);
    }

  }
  /// <summary>
  /// Bl wrapper around int.
  /// </summary>
  public partial class IntBl : AddBl<int, IntBl> {
    public static implicit operator IntBl(int d) { return new IntBl(Operations.Make(d)); }
    public static implicit operator IntBl(Random r) { return Expr<int>.FromFunc(r.Next); }
    private IntBl(Expr<int> Underlying) : base(Underlying) { }
    static IntBl() {
      Plus.Apply = (a, b) => a + b;
      Minus.Apply = (a, b) => a - b;
      ClampOp.Expand = (a, min, max) => (a.Bl() < min.Bl()).Condition(min, (a.Bl() > max.Bl()).Condition(max, a));
      ClampOp.Apply = (a, min, max) => a.Clamp(min, max);


      Register(v => new IntBl(v));
    }
    public static implicit operator IntBl(Expr<int> v) { return new IntBl(v); }

    /*

    public static DoubleBl operator -(IntBl i0, DoubleBl d0) {
      return ((DoubleBl)i0) - d0;
    }*/

    protected static readonly Operator<int, int, int> MultiplyOp = new Operator<int, int, int>(Markers.MultiplyMarker) {
      Apply = (x,y) => x * y,
      //Inverse0 = (r,y) => Brand(r) / Brand(y)
    };
    protected static readonly Operator<int, int, int> DivideOp = new Operator<int, int, int>(Markers.DivideMarker) {
      Apply = (x, y) => x / y,
      //Inverse0 = (r, y) => Brand(r) * Brand(y)
    };
    protected static readonly Operator<int, int, int> ModOp = new Operator<int, int, int>(Markers.ModMarker) {
      Apply = (x, y) => x % y,
    };
    protected static readonly Operator<int, int, int> MinOp = new Operator<int, int, int>(Markers.MinMarker) {
      Apply = (x, y) => Math.Min(x,y),
    };
    protected static readonly Operator<int, int, int> MaxOp = new Operator<int, int, int>(Markers.MaxMarker) {
      Apply = (x, y) => Math.Max(x, y),
    };
    public IntBl Min(IntBl other) { return MinOp.Make(this, other); }
    public IntBl Max(IntBl other) { return MaxOp.Make(this, other); }


    protected static readonly Operator<int, double> ToDoubleOp = new Operator<int, double>(Markers.IntToDouble) {
      Apply = (x) => x,
      Inverse = (x) => (IntBl) ((DoubleBl) x),
    };
    public static implicit operator DoubleBl(IntBl i) {
      return ToDoubleOp.Make(i).Bl();
    }
    /// <summary>
    /// Normalize an integer index to a value between 0 and max.
    /// </summary>
    /// <param name="max">Upper bound of normizations (exclusive).</param>
    /// <returns>A value between 0 and max.</returns>
    public IntBl Normalize(IntBl max) {
      IntBl ret = this;
      ret = ret % max;
      ret = (ret < 0).Condition(max + ret, ret);
      return ret;
    }
    /// <summary>
    /// Normalize an integer index to between 0 and max assuming it is a positive value (>= 0).
    /// </summary>
    /// <param name="max">Upper bound of normizations (exclusive).</param>
    /// <returns>A value between 0 and max.</returns>
    public IntBl NormalizeUp(IntBl max) {
      return this % max;
    }
    /// <summary>
    /// Normalize an integer index to between 0 and max assuming it is less than max.
    /// </summary>
    /// <param name="max">Upper bound of normizations (exclusive).</param>
    /// <returns>A value between 0 and max.</returns>
    public IntBl NormalizeDown(IntBl max) {
      return (this < 0).Condition(max + this, this);
    }
    public static IntBl operator *(IntBl op0, IntBl op1) { return MultiplyOp.Make(op0, op1).Bl(); }
    public static IntBl operator /(IntBl op0, IntBl op1) { return DivideOp.Make(op0, op1).Bl(); }
    public static IntBl operator %(IntBl op0, IntBl op1) { return ModOp.Make(op0, op1).Bl(); }


    protected static readonly Operator<int, int, bool> GreaterEqualOp = new Operator<int, int, bool>(Markers.GreaterEqualMarker) {
      Apply = (x, y) => x >= y,
    };
    protected static readonly Operator<int, int, bool> LessEqualOp = new Operator<int, int, bool>(Markers.LessEqualMarker) {
      Apply = (x, y) => x <= y,
    };
    protected static readonly Operator<int, int, bool> GreaterOp = new Operator<int, int, bool>(Markers.GreaterMarker) {
      Apply = (x, y) => x > y,
    };
    protected static readonly Operator<int, int, bool> LessOp = new Operator<int, int, bool>(Markers.LessMarker) {
      Apply = (x, y) => x < y,
    };
    public static BoolBl operator >=(IntBl arg0, IntBl arg1) {
      return (GreaterEqualOp.Make(arg0, arg1));
    }
    public static BoolBl operator <=(IntBl arg0, IntBl arg1) {
      return (LessEqualOp.Make(arg0, arg1));
    }
    public static BoolBl operator >(IntBl arg0, IntBl arg1) {
      return (GreaterOp.Make(arg0, arg1));
    }
    public static BoolBl operator <(IntBl arg0, IntBl arg1) {
      return (LessOp.Make(arg0, arg1));
    }
    public override IntBl LerpX(IntBl to, DoubleBl t) {
      return (IntBl) t.Lerp((DoubleBl)this, (DoubleBl)to);
    }
  }
  /// <summary>
  /// Bl wrapper around bool.
  /// </summary>
  public partial class BoolBl : CoreBl<bool, BoolBl> {
    private BoolBl(Expr<bool> Underlying) : base(Underlying) { }
    static BoolBl() {
      Register(v => new BoolBl(v));
    }
    public static implicit operator BoolBl(Expr<bool> v) { return new BoolBl(v); }
    public static implicit operator BoolBl(Expr<bool?> v) { return v.Map<bool>(b => b == null ? false : (bool) b, b => b); }
    public static implicit operator BoolBl(bool v) { return Operations.Make(v); }
    protected static readonly Operator<bool, bool, bool> And = new Operator<bool, bool, bool>(Markers.AndMarker) {
      Apply = (a, b) => a && b,
    };
    protected static readonly Operator<bool, bool, bool> Or = new Operator<bool, bool, bool>(Markers.OrMarker) {
      Apply = (a, b) => a || b,
    };
    protected static readonly Operator<bool, bool> Not = new Operator<bool, bool>(Markers.NotMarker) {
      Apply = (a) => !a,
    };
    public static BoolBl operator |(BoolBl opA, BoolBl opB) { return Or.Make(opA, opB); }
    public static BoolBl operator &(BoolBl opA, BoolBl opB) { return And.Make(opA, opB); }
    public static BoolBl operator !(BoolBl opA) { return Not.Make(opA); }

    /// <summary>
    /// Bare bones condition operation.
    /// </summary>
    /// <typeparam name="T">Core value type of arguments/results.</typeparam>
    /// <typeparam name="SELF">Branded Bl value type of arguments/result.</typeparam>
    /// <param name="ifTrue">Result when this is true.</param>
    /// <param name="ifFalse">Result when this is false.</param>
    /// <returns>ifTrue or ifFalse, depending on the current value of this.</returns>
    public BRAND Condition0<BRAND>(BRAND ifTrue, BRAND ifFalse) where BRAND : Brand, BaseBrand<BRAND> {
      return (BRAND) Conditions[typeof(BRAND)](this, ifTrue, ifFalse);
    }
    public Expr<S> Condition1<S>(Expr<S> ifTrue, Expr<S> ifFalse) {
      return Expr<S>.ConditionOp.Make(this, ifTrue, ifFalse);
    }

    public RadianAngleBl Condition(RadianAngleBl ifTrue, RadianAngleBl ifFalse) {
      return Expr<double>.ConditionOp.Make(this, ifTrue.Underlying, ifFalse.Underlying).Bl().ToRadians();
    }
    public DegreeAngleBl Condition(DegreeAngleBl ifTrue, DegreeAngleBl ifFalse) {
      return Expr<double>.ConditionOp.Make(this, ifTrue.Underlying, ifFalse.Underlying).Bl().ToDegrees();
    }
    public DoubleBl Condition(DoubleBl ifTrue, DoubleBl ifFalse) {
      return Expr<double>.ConditionOp.Make(this, ifTrue, ifFalse).Bl();
    }
    public IntBl Condition(IntBl ifTrue, IntBl ifFalse) {
      return Expr<int>.ConditionOp.Make(this, ifTrue, ifFalse).Bl();
    }
    public BoolBl Condition(BoolBl ifTrue, BoolBl ifFalse) {
      return Expr<bool>.ConditionOp.Make(this, ifTrue, ifFalse).Bl();
    }
    public StringBl Condition(StringBl ifTrue, StringBl ifFalse) {
      return Expr<string>.ConditionOp.Make(this, ifTrue, ifFalse).Bl();
    }
    public override BoolBl LerpX(BoolBl to, DoubleBl t) {
      return (t.Lerp(this.ToDouble(), to.ToDouble()) < 0.5).Condition(true, false);
    }
    /// <summary>
    /// turn the boolBl value to doubleBl type
    /// </summary>
    public DoubleBl ToDouble() {
      return Condition(1d, 0d); 
    }
  }

  public abstract partial class AngleBl<BRAND> : AddBl<double,BRAND> where BRAND : AngleBl<BRAND> {
    public static DegreeAngleBl FromDegrees(DoubleBl d) { return new DegreeAngleBl(d); }
    public static RadianAngleBl FromRadians(DoubleBl d) { return new RadianAngleBl(d); }

    /// <summary>
    /// Round this angle as (a * d).Round / d.
    /// </summary>
    /// <param name="d">Rounding value.</param>
    /// <returns>Rounded angle.</returns>
    public BRAND RoundN(DoubleBl d) { return ToBrand((Underlying.Bl() * d).Round / d); }

    public AngleBl(DoubleBl Underlying) : base(Underlying) { }
    public abstract DoubleBl Radians { get; }
    public abstract DoubleBl Degrees { get; }
    public DoubleBl Underlying0 { get { return Underlying; } }
    /// <summary>
    /// Normalize angle so that it is a value between 0 and MaxAngle.
    /// </summary>
    public BRAND Normalize {
      get {
        DoubleBl d = Underlying;
        d = d % MaxAngle.Underlying0;
        return ToBrand((d < 0).Condition(MaxAngle.Underlying0 + d, d));
      }
    }

    /// <summary>
    /// Normalize angle assuming it is less than max angle.
    /// </summary>
    public BRAND NormalizeUp {
      get {
        DoubleBl d = Underlying;
        return ToBrand((d < 0).Condition(MaxAngle.Underlying0 + d, d));
      }
    }


    /// <summary>
    /// Convert the angle to the degrees type
    /// </summary>
    /// <param name="d">the angle to be described</param>
    public static explicit operator DegreeAngleBl(AngleBl<BRAND> d) { return new DegreeAngleBl(d.Degrees); }
     /// <summary>
    /// Convert the angle to the radians type
    /// </summary>
    /// <param name="d">the angle to be described</param>
    /// <returns></returns>
   public static explicit operator RadianAngleBl(AngleBl<BRAND> d) { return new RadianAngleBl(d.Radians); }
    /// <summary>
    /// Describe the angle with degrees type
    /// </summary>
    /// <param name="d">the angle to be described</param>
    /// <returns></returns>
    public DegreeAngleBl ToDegrees() { return (DegreeAngleBl)this; } 
     /// <summary>
    /// Describe the angle with radians type
    /// </summary>
    /// <param name="d">the angle to be described</param>
    /// <returns></returns>
    public RadianAngleBl ToRadians() { return (RadianAngleBl)this; }

    public RadianAngleBl AsRadians { set { ToRadians().Bind = value; } }

    static AngleBl() {
      Plus.Apply = (a, b) => a + b;
      Minus.Apply = (a, b) => a - b;
      ClampOp.Apply = (a, b, c) => a.Clamp(b, c);
    }
    /// <summary>
    /// Maximum normal angle value.
    /// </summary>
    public static BRAND MaxAngle { get; protected set; }
    /// <summary>
    /// Maximum angle based on underlying value.
    /// </summary>
    /// <param name="other">Value to compare with</param>
    /// <returns>Max value</returns>
    public BRAND Max(BRAND other) { return ToBrand(Underlying.Bl().Max(other.Underlying)); }
    /// <summary>
    /// Minimum angle based on underlying value.
    /// </summary>
    /// <param name="other">Value to compare with</param>
    /// <returns>Min value</returns>
    public BRAND Min(BRAND other) { return ToBrand(Underlying.Bl().Min(other.Underlying)); }

    /// <summary>
    /// AdjustFromMath
    /// </summary>
    /// <param name="r"></param>
    /// <returns>-r+π/2</returns>
    protected static DoubleBl AdjustFromMathX(DoubleBl r) {
      r = 2d.Bl() * Math.PI - r;
      r = r - 1.5d.Bl() * Math.PI;
      return r;
    }
    /// <summary>
    /// AdjustToMath
    /// </summary>
    /// <param name="r"></param>
    /// <returns>-r-π/2</returns>
    protected static DoubleBl AdjustToMathX(DoubleBl r) {
      r = r + 1.5d.Bl() * Math.PI;
      r = 2d.Bl() * Math.PI - r;
      return r;
    }
    // if there is a quick change.
    /// <summary>
    /// simple lerp just return from + t*(to - from)
    /// </summary>
    /// <param name="from"></param>
    /// <param name="to"></param>
    /// <param name="t"></param>
    /// <returns></returns>
    public static BRAND QuickLerp(BRAND from, BRAND to, DoubleBl t) {
      return ToBrand(t.Lerp(from.Underlying0, to.Underlying0));
    }
    /// <summary>
    /// lerp in the smaller interval of the annular region [0, max angle] between angle "from" and "to"
    /// </summary>
    /// <param name="from"></param>
    /// <param name="to"></param>
    /// <param name="t"></param>
    /// <returns></returns>
    public static BRAND SafeLerp(BRAND from, BRAND to, DoubleBl t) {
      var diff = (to.Underlying0 - from.Underlying0);
      diff = (diff.Abs > MaxAngle.Underlying0 / 2d).Condition(-1d * (MaxAngle.Underlying0 - (diff.Abs % MaxAngle.Underlying0)) * diff.Sign, diff);
      return ToBrand(from.Underlying0 + diff * t);
    }
    /// <summary>
    /// A safe clamp for angles.
    /// </summary>
    /// <param name="min"></param>
    /// <param name="max"></param>
    /// <returns></returns>
    public new BRAND Clamp(BRAND min, BRAND max) {
      var diff = this.Underlying0 - min.Underlying0;
      var half = MaxAngle.Underlying0 / 2d;
      diff = (diff.Abs > half).Condition((MaxAngle.Underlying0 - diff.Abs) * -1d * diff.Sign, diff);
      return 
        (diff < half * -.5).Condition0(max, (diff < 0).Condition0(min, (BRAND) this)); //(diff > min.Underlying0 - max.Underlying0).Condition<double,SELF>(max, this));
    }

    public override BRAND LerpX(BRAND to, DoubleBl t) {
      return AngleBl<BRAND>.SafeLerp(this, to, t);
    }
    /// <summary>
    /// get the Inverse of this angle
    /// </summary>
    public BRAND Inverse {
      get {
        return ToBrand(MaxAngle.Underlying0 - (Underlying0)); }
    }
    public static BRAND operator *(AngleBl<BRAND> op, DoubleBl d) {
      return ToBrand(op.Underlying0 * d);
    }
    public static BRAND operator /(AngleBl<BRAND> op, DoubleBl d) {
      return ToBrand(op.Underlying0 / d);
    }
    public static DoubleBl operator /(AngleBl<BRAND> op, BRAND d) {
      return (op.Underlying0 / d.Underlying0);
    }
    protected static readonly Operator<double, double> SinOp = new Operator<double, double>(Markers.SinMarker) {
      Apply = (a) => Math.Sin(a),
    };
    protected static readonly Operator<double, double> CosOp = new Operator<double, double>(Markers.CosMarker) {
      Apply = (a) => Math.Cos(a),
    };
    protected static readonly Operator<double, double> TanOp = new Operator<double, double>(Markers.TanMarker) {
      Apply = (a) => Math.Tan(a),
    };
    /// <summary>
    /// Returns the sine of the specified angle.
    /// </summary>
    public DoubleBl Sin { get { return SinOp.Make(Radians); } }
    /// <summary>
    /// Returns the cosine of the specified angle.
    /// </summary>
    public DoubleBl Cos { get { return CosOp.Make(Radians); } }
    /// <summary>
    /// Returns the tangent of the specified angle.
    /// </summary>
    public DoubleBl Tan { get { return TanOp.Make(Radians); } }
    public static readonly Operator<double, double, double> ATan2Op = new Operator<double, double, double>(Markers.ATan2Marker) {
      Apply = (x, y) => (Math.Atan2(x, y)),
    };

    /// <summary>
    /// return the angle between the line(p0,(0,0)) and the line ((0,0),p1)
    /// </summary>
    /// <param name="p0">the first vertex to form the angle</param>
    /// <param name="p1">the second vertex to form the angle</param>
    /// <returns></returns>
    public static RadianAngleBl AngleBetween(PointBl p0, PointBl p1) {
      var a0 = ((DoubleBl)ATan2Op.Make(p1.Y, p1.X)) - ATan2Op.Make(p0.Y, p0.X);
      return new RadianAngleBl(/*AdjustToMath */ (a0));
    }

    public static BoolBl operator >(AngleBl<BRAND> op0, AngleBl<BRAND> op1) {
      return op0.Underlying.Bl() > op1.Underlying.Bl();
    }
    public static BoolBl operator <(AngleBl<BRAND> op0, AngleBl<BRAND> op1) {
      return op0.Underlying.Bl() < op1.Underlying.Bl();
    }
    public static BoolBl operator <=(AngleBl<BRAND> op0, AngleBl<BRAND> op1) {
      return op0.Underlying.Bl() <= op1.Underlying.Bl();
    }
    public static BoolBl operator >=(AngleBl<BRAND> op0, AngleBl<BRAND> op1) {
      return op0.Underlying.Bl() >= op1.Underlying.Bl();
    }

  }
  /// <summary>
  /// Tuple of two degree angles.
  /// </summary>
  public class DegreePointBl {
    private readonly Expr<double> X0;
    private readonly Expr<double> Y0;
    public DegreePointBl(DegreeAngleBl X, DegreeAngleBl Y) {
      this.X0 = X; this.Y0 = Y;
    }
    public DegreeAngleBl X { get { return X0.Bl().ToDegrees(); } set { X.Bind = value; } }
    public DegreeAngleBl Y { get { return Y0.Bl().ToDegrees(); } set { Y.Bind = value; } }
    public DegreePointBl Bind {
      get { return this; }
      set {
        X.Bind = value.X;
        Y.Bind = value.Y;
      }
    }
  }
  /// <summary>
  /// Tuple of three degree angles.
  /// </summary>
  public class DegreePoint3DBl {
    private readonly Expr<double> X0;
    private readonly Expr<double> Y0;
    private readonly Expr<double> Z0;
    public DegreePoint3DBl(DegreeAngleBl X, DegreeAngleBl Y, DegreeAngleBl Z) {
      this.X0 = X; this.Y0 = Y; this.Z0 = Z;
    }
    public DegreeAngleBl X { get { return X0.Bl().ToDegrees(); } set { X.Bind = value; } }
    public DegreeAngleBl Y { get { return Y0.Bl().ToDegrees(); } set { Y.Bind = value; } }
    public DegreeAngleBl Z { get { return Z0.Bl().ToDegrees(); } set { Z.Bind = value; } }
    public DegreePoint3DBl Bind {
      get { return this; }
      set {
        X.Bind = value.X;
        Y.Bind = value.Y;
        Z.Bind = value.Z;
      }
    }
  }

  /// <summary>
  /// Angle in radians.
  /// </summary>
  public partial class DegreeAngleBl : AngleBl<DegreeAngleBl> {
    /// <summary>
    /// Returns degree angle which converts from the type radians
    /// </summary>
    /// <param name="d">the angle with the type radians</param>
    /// <returns></returns>
    public new static DegreeAngleBl FromRadians(DoubleBl d) { return new RadianAngleBl(d).ToDegrees(); }
    public DegreeAngleBl(DoubleBl Underlying) : base(Underlying) { }
    /// <summary>
    /// Gets this angle as the degrees type
    /// </summary>
    public override DoubleBl Degrees {
      get { return Underlying; }
    }
    /// <summary>
    /// Gets this angle as the radians type
    /// </summary>
    public override DoubleBl Radians {
      get {
        return /* AdjustToMath */ (Degrees / (180.0 / Math.PI));
      }
    }
    public RadianAngleBl ToSimpleRadians() {
        return new RadianAngleBl((Degrees * (180.0 / Math.PI)));
    }


    /// <summary>
    /// Converts the angel to string type with suffix "_deg"
    /// </summary>
    public override string ToString() {
      return Underlying + "_deg";
    }
    public override DegreeAngleBl LerpX(DegreeAngleBl to, DoubleBl t) {
      return new DegreeAngleBl(t.Lerp(Underlying, to.Underlying));
    }
    static DegreeAngleBl() {
      Register(d => new DegreeAngleBl(d));
      MaxAngle = new DegreeAngleBl(360d);
    }
  }
  /// <summary>
  /// Describe the angle as the degrees type
  /// </summary>
  public partial class RadianAngleBl : AngleBl<RadianAngleBl> {
    /// <summary>
    /// Returns radians angle which converts from the type degree
    /// </summary>
    /// <param name="d">the angle with the type degrees</param>
    /// <returns></returns>
    public new static RadianAngleBl FromDegrees(DoubleBl d) { return new DegreeAngleBl(d).ToRadians(); }
    public RadianAngleBl(DoubleBl Underlying) : base(Underlying) { }
    /// <summary>
    /// Gets this angle as the radians type
    /// </summary>
    public override DoubleBl Radians {
      get { return Underlying; }
    }
    /// <summary>
    /// Converts the angel to string type with suffix "_rad"
    /// </summary>
    public override string ToString() {
      return Underlying + "_rad";
    }
    /// <summary>
    /// Gets this angle as the degrees type
    /// </summary>
    public override DoubleBl Degrees {
      get {
        return /* AjdustFromMath */ (Radians) * (180.0 / Math.PI);
      }
    }
    /// <summary>
    /// Converts the angel to stringBl in PI format.
    /// </summary>
    public override StringBl ToStringBl() {
        return  PI.ToStringBl() + " PI";
    }
    public StringBl ToStringBl(DoubleBl round) {
      return ((PI * round).Round / round).ToStringBl() + " PI";
    }


    public DoubleBl PI { get { return Radians / Math.PI; } }

    public override RadianAngleBl LerpX(RadianAngleBl to, DoubleBl t) {
      return new RadianAngleBl(t.Lerp(Underlying, to.Underlying));
    }
    /// <summary>
    /// Maximum radian angle.
    /// </summary>
    /// <remarks>Repeated here so static initialization will occur.</remarks>
    public static new RadianAngleBl MaxAngle {
      get {
        return AngleBl<RadianAngleBl>.MaxAngle;
      }
    }

    static RadianAngleBl() {
      Register(d => new RadianAngleBl(d));
      AngleBl<RadianAngleBl>.MaxAngle = new RadianAngleBl(2d * Math.PI);
    }
  }
  public abstract class VectorWorld<WORLD> where WORLD : VectorWorld<WORLD> { }
  public abstract class VectorSet<T,BRAND,WORLD> where BRAND : Brand<T,BRAND> where WORLD : VectorWorld<WORLD> {
    public static VectorSet<T, BRAND, WORLD> Instance { get; private set; }
    public VectorSet() {
      (Instance == null).Assert();
      Instance = this;
    }
    public interface VND<SELF> : BaseBrandT<T> where SELF : VND<SELF> { }
    public interface V2D : VND<V2D> {
      BRAND X { get; }
      BRAND Y { get; }
    }
    public interface V3D : VND<V3D> {
      BRAND X { get; }
      BRAND Y { get; }
      BRAND Z { get; }
    }
    public interface V4D : VND<V4D> {
      BRAND X { get; }
      BRAND Y { get; }
      BRAND Z { get; }
      BRAND W { get; }
    }
  }
  public abstract class DoubleVectorSet<WORLD> : VectorSet<double, DoubleBl, WORLD> where WORLD : VectorWorld<WORLD> {
    public new static DoubleVectorSet<WORLD> Instance { get { return (DoubleVectorSet<WORLD>)VectorSet<double, DoubleBl, WORLD>.Instance; } }
    public new interface VND<SELF> : VectorSet<double, DoubleBl, WORLD>.VND<SELF> where SELF : VND<SELF> {
    }
    public new interface V2D : VectorSet<double, DoubleBl, WORLD>.V2D, VND<V2D> {
    }
    public new interface V3D : VectorSet<double, DoubleBl, WORLD>.V2D, VND<V3D> {
    }
    public new interface V4D : VectorSet<double, DoubleBl, WORLD>.V2D, VND<V4D> {
    }
  }
  public abstract class BoolVectorSet<WORLD> : VectorSet<bool, BoolBl, WORLD> where WORLD : VectorWorld<WORLD> {
    public new static BoolVectorSet<WORLD> Instance { get { return (BoolVectorSet<WORLD>)VectorSet<bool, BoolBl, WORLD>.Instance; } }
  }




  public partial interface BasePointBl : BaseBrand {
    PointBl XY { get; set; }
    BasePointBl Add(BasePointBl Other);
    BasePointBl Mult(BasePointBl Other);
    BasePointBl Mult(DoubleBl Other);
    BasePointBl Div(BasePointBl Other);
    BasePointBl Div(DoubleBl Other);
  }
  public interface PointBl<T, BRAND> : BaseBrand<T, BRAND>, BasePointBl where BRAND : Brand<T,BRAND>, PointBl<T,BRAND> {}
  public abstract partial class PointBl<T, BRAND, ARITY> : RealTupleBl<T, BRAND, ARITY>, PointBl<T,BRAND>
    where BRAND : PointBl<T, BRAND, ARITY>
    where ARITY : ArityInfo<T, ARITY>, new() {
    // + on multi-values. 
    protected static readonly AssociativeOperator<T, T> Multiply = new AssociativeOperator<T, T>(Markers.MultiplyMarker) {
      Apply = Arity.F((aa, bb) => aa * bb),
    };
    protected static readonly Operator<T, T, T> Divide = new Operator<T, T, T>(Markers.DivideMarker) { 
      Apply = (a,b) => {
        var ret = Arity.F((aa,bb) => aa / bb)(a,b);
        return ret;
      },
    };
    protected static readonly Operator<T, T, T> Mod = new Operator<T, T, T>(Markers.ModMarker) {
      Apply = Arity.F((aa, bb) => aa % bb),
    };
    protected static readonly Operator<T, double, T> PlusX = new Operator<T, double, T>(Markers.PlusMarker) {
      Apply = (t,d) => Arity.Map(x => x + d)(t),
    };
    protected static readonly Operator<T, double, T> MinusX = new Operator<T, double, T>(Markers.MinusMarker) {
      Apply = (t, d) => Arity.Map(x => x - d)(t),
    };
    public PointBl(Expr<T> Underlying) : base(Underlying) { }
    static PointBl() {
      Multiply.Inverse0 = Divide.Make;
      Divide.Inverse0 = Multiply.Make;
      Divide.Inverse1 = (x, y) => Divide.Make(y, x);
      PlusX.Inverse0 = (a, c) => MinusX.Make(a, c);
      MinusX.Inverse0 = (a, c) => PlusX.Make(a, c);
      IsNanOp.Expand = (p) => {
        var b = ToBrand(p);
        BoolBl result = false;
        for (int i = 0; i < Arity.Arity; i++) {
          result = result | b[i].IsNaN;
        }
        return result;
      };
      var TName = typeof(T).FullName;

      MultiplyX.Linq = (e1, e2) =>
        linq.Expression.Convert(linq.Expression.Multiply(linq.Expression.Convert(e1, VectorType), e2), typeof(T));
      MultiplyX.AsText = (e1, e2) => {
        var ret = tcast(vcast(e1) + " * " + e2);
        return ret;
      };
      DivideX.Linq = (e1, e2) =>
        linq.Expression.Convert(linq.Expression.Divide(linq.Expression.Convert(e1, VectorType), e2), typeof(T));
      DivideX.AsText = (e1, e2) => tcast(vcast(e1) + " / " + e2);

      var TARGET = typeof(BRAND).FullName;
      PlusX.Linq = (e1, e2) =>
        linq.Expression.Call(typeof(BRAND), "Plus0", new Type[] { }, e1, e2);
      PlusX.AsText = (e1, e2) => TARGET + ".Plus0(" + e1 + ", " + e2 + ")";

      MinusX.Linq = (e1, e2) =>
        linq.Expression.Call(typeof(BRAND), "Minus0", new Type[] { }, e1, e2);
      MinusX.AsText = (e1, e2) => TARGET + ".Minus0(" + e1 + ", " + e2 + ")";

      Multiply.Linq = (e1, e2) =>
        linq.Expression.Call(typeof(BRAND), "Mult", new Type[] { }, e1, e2);
      Multiply.AsText = (e1, e2) => TARGET + ".Mult(" + e1 + ", " + e2 + ")";

      Divide.Linq = (e1, e2) =>
        linq.Expression.Call(typeof(BRAND), "Div", new Type[] { }, e1, e2);
      Divide.AsText = (e1, e2) => TARGET + ".Div(" + e1 + ", " + e2 + ")";


      Mod.Linq = (e1, e2) =>
        linq.Expression.Call(typeof(BRAND), "Mod0", new Type[] { }, e1, e2);
      Mod.AsText = (e1, e2) => TARGET + ".Mod0(" + e1 + ", " + e2 + ")";

    }
    public abstract PointBl XY { get; set;  }
    [Obsolete("Use + operator instead.")]
    public BasePointBl Add(BasePointBl Other) {
      return this + ((BRAND)Other);
    }
    [Obsolete("Use * operator instead.")]
    public BasePointBl Mult(BasePointBl Other) {
      return this * ((BRAND)Other);
    }
    [Obsolete("Use * operator instead.")]
    public BasePointBl Mult(DoubleBl Other) {
      return this * (Other);
    }
    [Obsolete("Use / operator instead.")]
    public BasePointBl Div(BasePointBl Other) {
      return this / ((BRAND)Other);
    }
    [Obsolete("Use / operator instead.")]
    public BasePointBl Div(DoubleBl Other) {
      return this / (Other);
    }

    public static BRAND operator -(PointBl<T, BRAND, ARITY> op0, DoubleBl op1) {
      return ToBrand(MinusX.Make(op0, op1));
    }
    public static BRAND operator +(PointBl<T, BRAND, ARITY> op0, DoubleBl op1) {
      return ToBrand(PlusX.Make(op0, op1));
    }

    public static BRAND operator *(PointBl<T, BRAND, ARITY> op0, BRAND op1) {
      Expr<T> result = Multiply.Make(op0, op1);
      return ToBrand(result);
    }
    public static BRAND operator *(DoubleBl op0, PointBl<T, BRAND, ARITY> op1) { return op1 * op0; }
    public static BRAND operator /(PointBl<T, BRAND, ARITY> op0, BRAND op1) {
      Expr<T> result = Divide.Make(op0, op1);
      return ToBrand(result);
    }
    public static BRAND operator %(PointBl<T, BRAND, ARITY> op0, BRAND op1) {
      Expr<T> result = Mod.Make(op0, op1);
      return ToBrand(result);
    }
    public static BRAND operator %(PointBl<T, BRAND, ARITY> op0, DoubleBl op1) {
      BRAND op2;
      Expr<double>[] d = new Expr<double>[Arity.Arity];
      for (int i = 0; i < Arity.Arity; i++) {
        d[i] = op1;
      }
      op2 = ToBrand(ArityInfo<T, ARITY>.ArityExpr.Make(d));
      return op0 % op2;
    }
    public BRAND Frac {
      get {
        Expr<double>[] d = new Expr<double>[Arity.Arity];
        for (int i = 0; i < Arity.Arity; i++) {
          d[i] = this[i].Frac;
        }
        return ToBrand(ArityInfo<T, ARITY>.ArityExpr.Make(d));
      } 
    }

    public static BRAND operator *(T op0, PointBl<T, BRAND, ARITY> op1) {
      Expr<T> result = Multiply.Make(Operations.Make(op0), op1);
      return ToBrand(result);
    }
    public static BRAND operator /(T op0, PointBl<T, BRAND, ARITY> op1) {
      Expr<T> result = Divide.Make(Operations.Make(op0), op1);
      return ToBrand(result);
    }
    public static BRAND operator %(T op0, PointBl<T, BRAND, ARITY> op1) {
      Expr<T> result = Mod.Make(Operations.Make(op0), op1);
      return ToBrand(result);
    }
    /// <summary>
    /// Unit vector of point around origin.
    /// </summary>
    public BRAND Normal {
      get { return this / Length; }
    }

  }
  enum X { fff, ggg, hhh };


  public partial class EnumBl<T> : Brand<T, EnumBl<T>> {
    public EnumBl(Expr<T> v) : base(v) { }
    public static implicit operator EnumBl<T>(Expr<T> v) { return new EnumBl<T>(v); }
    public static implicit operator EnumBl<T>(T v) { return new Constant<T>(v); }
    static EnumBl() {
      Register(v => v);
    }
  }

  public interface CollectionBl<E, EBRAND> : BaseBrand where EBRAND : Brand<E, EBRAND> {
    IList<EBRAND> AddMany { set; }
    void Add(params EBRAND[] value);
    EBRAND AddOne { set; }
  }

  /// <summary>
  /// Bling wrapper around collections.
  /// </summary>
  /// <typeparam name="E">Collection element type.</typeparam>
  /// <typeparam name="EBRAND">Bling type of collection element.</typeparam>
  /// <typeparam name="T">Original collection type.</typeparam>
  /// <typeparam name="BRAND">Bling type of collection.</typeparam>
  public abstract class CollectionBl<E, EBRAND, T, BRAND> : Brand<T, BRAND>, CollectionBl<E,EBRAND>
    where BRAND : CollectionBl<E, EBRAND, T, BRAND>
    where T : IList, ICollection, /* IList<E>, ICollection<E>, IEnumerable<E>, */ IEnumerable 
    where EBRAND : Brand<E, EBRAND> {
    public CollectionBl(Expr<T> Underlying) : base(Underlying) { }


    /// <summary>
    /// Add multiple elements to this collection using setter syntax. Useful for intilizers.
    /// </summary>
    public IList<EBRAND> AddMany {
      set {
        foreach (var e in value) this.CurrentValue.Add(e.CurrentValue);
      }
    }
    /// <summary>
    /// Add elements to this collection.
    /// </summary>
    public void Add(params EBRAND[] value) {
      AddMany = value;
    }

    /// <summary>
    /// Add one element to this collection using setter syntax. Useful for initializers.
    /// </summary>
    public EBRAND AddOne {
      set {
        this.CurrentValue.Add(value.CurrentValue);
      }
    }
  }
  /// <summary>
  /// For Bling wrappers around collections that don't require unique brands.
  /// </summary>
  /// <typeparam name="E">Collection element type.</typeparam>
  /// <typeparam name="EBRAND">Bling type of collection element.</typeparam>
  /// <typeparam name="T">Original collection type.</typeparam>
  public class CollectionBl<E, EBRAND, T> : CollectionBl<E, EBRAND, T, CollectionBl<E, EBRAND, T>>
    where T : IList, ICollection /*, IList<E>, ICollection<E>, IEnumerable<E> */, IEnumerable
    where EBRAND : Brand<E, EBRAND> {
    public CollectionBl(Expr<T> Underlying) : base(Underlying) { }
    //public CollectionBl() : this(new Constant<T>(new T())) { }
    public static implicit operator CollectionBl<E, EBRAND, T>(Expr<T> target) { return new CollectionBl<E, EBRAND, T>((target)); }
    public static implicit operator CollectionBl<E, EBRAND, T>(T target) { return (new Constant<T>(target)); }
    static CollectionBl() { Register(v => v); }
    /*
    public static implicit operator CollectionBl<E, EBRAND, T>(IList<EBRAND> values) {
      return new CollectionBl<E, EBRAND, T>() {

      };
    }
     */
  }
  public class CollectionXBl<E, EBRAND, T> : CollectionBl<E, EBRAND, T, CollectionBl<E, EBRAND, T>>
    where T : IList, ICollection, IList<E>, ICollection<E>, IEnumerable<E>, IEnumerable, new()
    where EBRAND : Brand<E, EBRAND> {
    public CollectionXBl(Expr<T> Underlying) : base(Underlying) { }
    public CollectionXBl() : this(new Constant<T>(new T())) { }
    public static implicit operator CollectionXBl<E, EBRAND, T>(Expr<T> target) { return new CollectionXBl<E, EBRAND, T>((target)); }
    public static implicit operator CollectionXBl<E, EBRAND, T>(T target) { return (new Constant<T>(target)); }
    static CollectionXBl() { Register(v => v); }
    public static implicit operator CollectionXBl<E, EBRAND, T>(EBRAND[] values) {
      return new CollectionXBl<E, EBRAND, T>() {
        AddMany = values, 
      };
    }
  }
  public interface PrimitiveCollectionBl<E, EBRAND> : CollectionBl<E,EBRAND> where EBRAND : Brand<E, EBRAND> {
    void InitElements(IList<EBRAND> Backing);
    Action RefreshAction(IList<EBRAND> Backing);
  }


  public static partial class BlExtensions {
    public static void Bind<BRAND>(this BRAND[] Values, params BRAND[] To) where BRAND : Brand, BaseBrand<BRAND> {
      (Values.Length == To.Length).Assert();
      for (int i = 0; i < Values.Length; i++)
        Values[i].Bind = To[i];
    }
    /// <summary>
    /// Bind these 4 points to the corners of a rectangle defined by Size, where the upper left corner is (0,0).
    /// </summary>
    /// <param name="Size">Size of rectangle to bind.</param>
    public static void BindRect(this PointBl[] Values, PointBl Size) {
      (Values.Length == 4).Assert();
      Values.Bind<PointBl>(new PointBl(0, 0), new PointBl(Size.X, 0),
                           Size, new PointBl(0, Size.Y));
    }



    public static BRAND Table<BRAND>(this BRAND[] Values, Expr<int> Index) where BRAND : Brand, BaseBrand<BRAND> {
      return (BRAND) Brand.Tables[typeof(BRAND)](Values, Index);
    }





    /// <summary>
    /// Convert unbranded Bl value to branded Bl value.
    /// </summary>
    /// <param name="d">Unbranded Bl value.</param>
    /// <returns>Branded Bl value.</returns>
    public static DoubleBl Bl(this Expr<double> d) { return d; }
    /// <summary>
    /// Convert unbranded Bl value to branded Bl value.
    /// </summary>
    /// <param name="d">Unbranded Bl value.</param>
    /// <returns>Branded Bl value.</returns>
    public static StringBl Bl(this Expr<string> d) { return d; }
    /// <summary>
    /// Convert unbranded Bl value to branded Bl value.
    /// </summary>
    /// <param name="d">Unbranded Bl value.</param>
    /// <returns>Branded Bl value.</returns>
    public static StringBl Bl(this string d) { return d; }
    /// <summary>
    /// Convert unbranded Bl value to branded Bl value.
    /// </summary>
    /// <param name="d">Unbranded Bl value.</param>
    /// <returns>Branded Bl value.</returns>
    public static IntBl Bl(this Expr<int> d) { return d; }
    /// <summary>
    /// Convert unbranded Bl value to branded Bl value.
    /// </summary>
    /// <param name="d">Unbranded Bl value.</param>
    /// <returns>Branded Bl value.</returns>
    public static BoolBl Bl(this Expr<bool> d) { return d; }
    /// <summary>
    /// Convert unbranded Bl value to branded Bl value.
    /// </summary>
    /// <param name="d">Unbranded Bl value.</param>
    /// <returns>Branded Bl value.</returns>
    public static ObjectBl Bl(this Expr<object> d) { return d; }

    public static Func<IntBl, DoubleBl> Bl(this Func<IntBl, Expr<double>> F) { return x => F(x).Bl(); }
    public static Func<IntBl, IntBl> Bl(this Func<IntBl, Expr<int>> F) { return x => F(x).Bl(); }
    public static Func<IntBl, BoolBl> Bl(this Func<IntBl, Expr<bool>> F) { return x => F(x).Bl(); }



    /// <summary>
    /// Convert core language value to branded Bl value.
    /// </summary>
    /// <param name="d">Core language value.</param>
    /// <returns>Branded Bl value.</returns>
    public static DoubleBl Bl(this double d) { return d; }

    /// <summary>
    /// Convert core language value to branded Bl value.
    /// </summary>
    /// <param name="d">Core language value.</param>
    /// <returns>Branded Bl value.</returns>
    public static IntBl Bl(this int d) { return d; }
    /// <summary>
    /// Convert core language value to branded Bl value.
    /// </summary>
    /// <param name="d">Core language value.</param>
    /// <returns>Branded Bl value.</returns>
    public static BoolBl Bl(this bool d) { return d; }
    /// <summary>
    /// Convert value into degree angle.
    /// </summary>
    /// <param name="d">Value of degrees to convert.</param>
    /// <returns>Degree angle.</returns>
    public static DegreeAngleBl ToDegrees(this double d) { return new DegreeAngleBl(d); }
    /// <summary>
    /// Convert value into degree angle.
    /// </summary>
    /// <param name="d">Value of degrees to convert.</param>
    /// <returns>Degree angle.</returns>
    public static DegreeAngleBl ToDegrees(this int d) { return new DegreeAngleBl(d); }
    /// <summary>
    /// Convert PI value into radian angle.
    /// </summary>
    /// <param name="d">Value of radian angle to convert according to PI (radians = d * Math.PI).</param>
    /// <returns>Radian angle.</returns>
    public static RadianAngleBl ToPI(this double d) { return new RadianAngleBl(d * Math.PI); }
    /// <summary>
    /// Convert PI value into radian angle.
    /// </summary>
    /// <param name="d">Value of radian angle to convert according to PI (radians = d * Math.PI).</param>
    /// <returns>Radian angle.</returns>
    public static RadianAngleBl ToPI(this int d) { return new RadianAngleBl(Math.PI * d); }
  }
  /// <summary>
  /// Any minimum/maximum property pair.
  /// </summary>
  public abstract class RangeSet<T, BRAND> where BRAND : AddBl<T, BRAND> {
    /// <summary>
    /// Maximum value of this range set.
    /// </summary>
    public abstract BRAND Maximum { get; set; }
    /// <summary>
    /// Minimum value of this range set. 
    /// </summary>
    public abstract BRAND Minimum { get; set; }
    public void Bind(RangeSet<T, BRAND> other) {
      Maximum.Bind = other.Maximum; Minimum.Bind = other.Minimum;
    }
  }
}
